blob: 6c236d5a04a31d9ced5b1e71c7969d85cbf60e4a [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Linux-specific syscalls, etc. syswrap-linux.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2005 Nicholas Nethercote
njn@valgrind.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "pub_core_basics.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_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_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-linux.h"
#include "vki_unistd.h" /* for the __NR_* constants */
// 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-linux",
"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_(set_running)(tid);
if (0)
VG_(printf)("thread tid %d started: stack = %p\n",
tid, &tid);
VG_TRACK ( post_thread_create, tst->os_state.parent, 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-linux",
"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-linux",
"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-linux",
"run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
(ULong)tidW);
c = VG_(count_living_threads)();
vg_assert(c >= 1); /* stay sane */
if (c == 1) {
VG_(debugLog)(1, "syswrap-linux",
"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-linux",
"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_linux)
asm volatile (
"movl %1, %0\n" /* set tst->status = VgTs_Empty */
"movl %2, %%eax\n" /* set %eax = __NR_exit */
"movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */
"int $0x80\n" /* exit(tst->os_state.exitcode) */
: "=m" (tst->status)
: "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode));
#elif defined(VGP_amd64_linux)
asm volatile (
"movl %1, %0\n" /* set tst->status = VgTs_Empty */
"movq %2, %%rax\n" /* set %rax = __NR_exit */
"movq %3, %%rdi\n" /* set %rdi = tst->os_state.exitcode */
"syscall\n" /* exit(tst->os_state.exitcode) */
: "=m" (tst->status)
: "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode));
#elif defined(VGP_ppc32_linux)
{ UInt vgts_empty = (UInt)VgTs_Empty;
asm volatile (
"stw %1,%0\n\t" /* set tst->status = VgTs_Empty */
"li 0,%2\n\t" /* set r0 = __NR_exit */
"lwz 3,%3\n\t" /* set r3 = tst->os_state.exitcode */
"sc\n\t" /* exit(tst->os_state.exitcode) */
: "=m" (tst->status)
: "r" (vgts_empty), "n" (__NR_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-linux",
"entering VG_(main_thread_wrapper_NORETURN)\n");
sp = ML_(allocstack)(tid);
#if defined(VGP_ppc32_linux)
/* make a stack frame */
sp -= 16;
sp &= ~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 clone which is really a fork() */
SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
Int* parent_tidptr, Int* child_tidptr )
{
vki_sigset_t fork_saved_mask;
vki_sigset_t mask;
SysRes res;
if (flags & (VKI_CLONE_SETTLS | VKI_CLONE_FS | VKI_CLONE_VM
| VKI_CLONE_FILES | VKI_CLONE_VFORK))
return VG_(mk_SysRes_Error)( VKI_EINVAL );
/* 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);
/* Since this is the fork() form of clone, we don't need all that
VG_(clone) stuff */
#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux)
res = VG_(do_syscall5)( __NR_clone, flags,
(UWord)NULL, (UWord)parent_tidptr,
(UWord)NULL, (UWord)child_tidptr );
#elif defined(VGP_amd64_linux)
/* note that the last two arguments are the opposite way round to x86 and
ppc32 as the amd64 kernel expects the arguments in a different order */
res = VG_(do_syscall5)( __NR_clone, flags,
(UWord)NULL, (UWord)parent_tidptr,
(UWord)child_tidptr, (UWord)NULL );
#else
# error Unknown platform
#endif
if (!res.isError && res.val == 0) {
/* child */
VG_(do_atfork_child)(tid);
/* restore signal mask */
VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
}
else
if (!res.isError && res.val > 0) {
/* parent */
if (VG_(clo_trace_syscalls))
VG_(printf)(" clone(fork): process %d created child %d\n",
VG_(getpid)(), res.val);
/* 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(linux, name)
#define POST(name) DEFN_POST_TEMPLATE(linux, name)
// Combine two 32-bit values into a 64-bit value
#define LOHI64(lo,hi) ( (lo) | ((ULong)(hi) << 32) )
/* ---------------------------------------------------------------------
*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( %p, %p, %p, %p, %p )" ,ARG1,ARG2,ARG3,ARG4,ARG5);
PRE_REG_READ5(long, "mount",
char *, source, char *, target, char *, type,
unsigned long, flags, void *, data);
PRE_MEM_RASCIIZ( "mount(source)", ARG1);
PRE_MEM_RASCIIZ( "mount(target)", ARG2);
PRE_MEM_RASCIIZ( "mount(type)", ARG3);
}
PRE(sys_oldumount)
{
PRINT("sys_oldumount( %p )", ARG1);
PRE_REG_READ1(long, "umount", char *, path);
PRE_MEM_RASCIIZ( "umount(path)", ARG1);
}
PRE(sys_umount)
{
PRINT("sys_umount( %p, %d )", ARG1, ARG2);
PRE_REG_READ2(long, "umount2", char *, path, int, flags);
PRE_MEM_RASCIIZ( "umount2(path)", ARG1);
}
/* ---------------------------------------------------------------------
16- and 32-bit uid/gid wrappers
------------------------------------------------------------------ */
PRE(sys_setfsuid16)
{
PRINT("sys_setfsuid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setfsuid16", vki_old_uid_t, uid);
}
PRE(sys_setfsuid)
{
PRINT("sys_setfsuid ( %d )", ARG1);
PRE_REG_READ1(long, "setfsuid", vki_uid_t, uid);
}
PRE(sys_setfsgid16)
{
PRINT("sys_setfsgid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setfsgid16", vki_old_gid_t, gid);
}
PRE(sys_setfsgid)
{
PRINT("sys_setfsgid ( %d )", ARG1);
PRE_REG_READ1(long, "setfsgid", vki_gid_t, gid);
}
PRE(sys_setresuid16)
{
PRINT("sys_setresuid16 ( %d, %d, %d )", ARG1, ARG2, ARG3);
PRE_REG_READ3(long, "setresuid16",
vki_old_uid_t, ruid, vki_old_uid_t, euid, vki_old_uid_t, suid);
}
PRE(sys_setresuid)
{
PRINT("sys_setresuid ( %d, %d, %d )", ARG1, ARG2, ARG3);
PRE_REG_READ3(long, "setresuid",
vki_uid_t, ruid, vki_uid_t, euid, vki_uid_t, suid);
}
PRE(sys_getresuid16)
{
PRINT("sys_getresuid16 ( %p, %p, %p )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "getresuid16",
vki_old_uid_t *, ruid, vki_old_uid_t *, euid,
vki_old_uid_t *, suid);
PRE_MEM_WRITE( "getresuid16(ruid)", ARG1, sizeof(vki_old_uid_t) );
PRE_MEM_WRITE( "getresuid16(euid)", ARG2, sizeof(vki_old_uid_t) );
PRE_MEM_WRITE( "getresuid16(suid)", ARG3, sizeof(vki_old_uid_t) );
}
POST(sys_getresuid16)
{
vg_assert(SUCCESS);
if (RES == 0) {
POST_MEM_WRITE( ARG1, sizeof(vki_old_uid_t) );
POST_MEM_WRITE( ARG2, sizeof(vki_old_uid_t) );
POST_MEM_WRITE( ARG3, sizeof(vki_old_uid_t) );
}
}
PRE(sys_getresuid)
{
PRINT("sys_getresuid ( %p, %p, %p )", 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_setresgid16)
{
PRINT("sys_setresgid16 ( %d, %d, %d )", ARG1, ARG2, ARG3);
PRE_REG_READ3(long, "setresgid16",
vki_old_gid_t, rgid,
vki_old_gid_t, egid, vki_old_gid_t, sgid);
}
PRE(sys_setresgid)
{
PRINT("sys_setresgid ( %d, %d, %d )", ARG1, ARG2, ARG3);
PRE_REG_READ3(long, "setresgid",
vki_gid_t, rgid, vki_gid_t, egid, vki_gid_t, sgid);
}
PRE(sys_getresgid16)
{
PRINT("sys_getresgid16 ( %p, %p, %p )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "getresgid16",
vki_old_gid_t *, rgid, vki_old_gid_t *, egid,
vki_old_gid_t *, sgid);
PRE_MEM_WRITE( "getresgid16(rgid)", ARG1, sizeof(vki_old_gid_t) );
PRE_MEM_WRITE( "getresgid16(egid)", ARG2, sizeof(vki_old_gid_t) );
PRE_MEM_WRITE( "getresgid16(sgid)", ARG3, sizeof(vki_old_gid_t) );
}
POST(sys_getresgid16)
{
vg_assert(SUCCESS);
if (RES == 0) {
POST_MEM_WRITE( ARG1, sizeof(vki_old_gid_t) );
POST_MEM_WRITE( ARG2, sizeof(vki_old_gid_t) );
POST_MEM_WRITE( ARG3, sizeof(vki_old_gid_t) );
}
}
PRE(sys_getresgid)
{
PRINT("sys_getresgid ( %p, %p, %p )", 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
------------------------------------------------------------------ */
PRE(sys_exit_group)
{
ThreadId t;
ThreadState* tst;
PRINT("exit_group( %d )", 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_(kill_thread)(t); /* unblock it, if blocked */
}
/* We have to claim the syscall already succeeded. */
SET_STATUS_Success(0);
}
PRE(sys_llseek)
{
PRINT("sys_llseek ( %d, 0x%x, 0x%x, %p, %d )", ARG1,ARG2,ARG3,ARG4,ARG5);
PRE_REG_READ5(long, "llseek",
unsigned int, fd, unsigned long, offset_high,
unsigned long, offset_low, vki_loff_t *, result,
unsigned int, whence);
PRE_MEM_WRITE( "llseek(result)", ARG4, sizeof(vki_loff_t));
}
POST(sys_llseek)
{
vg_assert(SUCCESS);
if (RES == 0)
POST_MEM_WRITE( ARG4, sizeof(vki_loff_t) );
}
//zz PRE(sys_adjtimex, 0)
//zz {
//zz struct vki_timex *tx = (struct vki_timex *)ARG1;
//zz PRINT("sys_adjtimex ( %p )", ARG1);
//zz PRE_REG_READ1(long, "adjtimex", struct timex *, buf);
//zz PRE_MEM_READ( "adjtimex(timex->modes)", ARG1, sizeof(tx->modes));
//zz
#if 0 //zz (avoiding warnings about multi-line comments)
zz #define ADJX(bit,field) \
zz if (tx->modes & bit) \
zz PRE_MEM_READ( "adjtimex(timex->"#field")", \
zz (Addr)&tx->field, sizeof(tx->field))
#endif
//zz ADJX(ADJ_FREQUENCY, freq);
//zz ADJX(ADJ_MAXERROR, maxerror);
//zz ADJX(ADJ_ESTERROR, esterror);
//zz ADJX(ADJ_STATUS, status);
//zz ADJX(ADJ_TIMECONST, constant);
//zz ADJX(ADJ_TICK, tick);
//zz #undef ADJX
//zz
//zz PRE_MEM_WRITE( "adjtimex(timex)", ARG1, sizeof(struct vki_timex));
//zz }
//zz
//zz POST(sys_adjtimex)
//zz {
//zz POST_MEM_WRITE( ARG1, sizeof(struct vki_timex) );
//zz }
PRE(sys_ioperm)
{
PRINT("sys_ioperm ( %d, %d, %d )", ARG1, ARG2, ARG3 );
PRE_REG_READ3(long, "ioperm",
unsigned long, from, unsigned long, num, int, turn_on);
}
PRE(sys_syslog)
{
*flags |= SfMayBlock;
PRINT("sys_syslog (%d, %p, %d)", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "syslog", int, type, char *, bufp, int, len);
switch (ARG1) {
// The kernel uses magic numbers here, rather than named constants,
// therefore so do we.
case 2: case 3: case 4:
PRE_MEM_WRITE( "syslog(bufp)", ARG2, ARG3);
break;
default:
break;
}
}
POST(sys_syslog)
{
switch (ARG1) {
case 2: case 3: case 4:
POST_MEM_WRITE( ARG2, ARG3 );
break;
default:
break;
}
}
PRE(sys_vhangup)
{
PRINT("sys_vhangup ( )");
PRE_REG_READ0(long, "vhangup");
}
PRE(sys_sysinfo)
{
PRINT("sys_sysinfo ( %p )",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) );
}
PRE(sys_personality)
{
PRINT("sys_personality ( %llu )", (ULong)ARG1);
PRE_REG_READ1(long, "personality", vki_u_long, persona);
}
PRE(sys_sysctl)
{
struct __vki_sysctl_args *args;
PRINT("sys_sysctl ( %p )", ARG1 );
args = (struct __vki_sysctl_args *)ARG1;
PRE_REG_READ1(long, "sysctl", struct __sysctl_args *, args);
PRE_MEM_WRITE( "sysctl(args)", ARG1, sizeof(struct __vki_sysctl_args) );
if (!VG_(am_is_valid_for_client)(ARG1, sizeof(struct __vki_sysctl_args),
VKI_PROT_READ)) {
SET_STATUS_Failure( VKI_EFAULT );
return;
}
PRE_MEM_READ("sysctl(name)", (Addr)args->name, args->nlen * sizeof(*args->name));
if (args->newval != NULL)
PRE_MEM_READ("sysctl(newval)", (Addr)args->newval, args->newlen);
if (args->oldlenp != NULL) {
PRE_MEM_READ("sysctl(oldlenp)", (Addr)args->oldlenp, sizeof(*args->oldlenp));
PRE_MEM_WRITE("sysctl(oldval)", (Addr)args->oldval, *args->oldlenp);
}
}
POST(sys_sysctl)
{
struct __vki_sysctl_args *args;
args = (struct __vki_sysctl_args *)ARG1;
if (args->oldlenp != NULL) {
POST_MEM_WRITE((Addr)args->oldlenp, sizeof(*args->oldlenp));
POST_MEM_WRITE((Addr)args->oldval, 1 + *args->oldlenp);
}
}
PRE(sys_prctl)
{
*flags |= SfMayBlock;
PRINT( "prctl ( %d, %d, %d, %d, %d )", ARG1, ARG2, ARG3, ARG4, ARG5 );
// XXX: too simplistic, often not all args are used
// Nb: can't use "ARG2".."ARG5" here because that's our own macro...
PRE_REG_READ5(long, "prctl",
int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5);
// XXX: totally wrong... we need to look at the 'option' arg, and do
// PRE_MEM_READs/PRE_MEM_WRITEs as necessary...
}
PRE(sys_sendfile)
{
*flags |= SfMayBlock;
PRINT("sys_sendfile ( %d, %d, %p, %lu )", ARG1,ARG2,ARG3,ARG4);
PRE_REG_READ4(ssize_t, "sendfile",
int, out_fd, int, in_fd, vki_off_t *, offset,
vki_size_t, count);
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 ) );
}
}
PRE(sys_sendfile64)
{
*flags |= SfMayBlock;
PRINT("sendfile64 ( %d, %d, %p, %lu )",ARG1,ARG2,ARG3,ARG4);
PRE_REG_READ4(ssize_t, "sendfile64",
int, out_fd, int, in_fd, vki_loff_t *, offset,
vki_size_t, count);
if (ARG3 != 0)
PRE_MEM_WRITE( "sendfile64(offset)", ARG3, sizeof(vki_loff_t) );
}
POST(sys_sendfile64)
{
if (ARG3 != 0 ) {
POST_MEM_WRITE( ARG3, sizeof(vki_loff_t) );
}
}
PRE(sys_futex)
{
/*
arg param used by ops
ARG1 - u32 *futex all
ARG2 - int op
ARG3 - int val WAIT,WAKE,FD,REQUEUE,CMP_REQUEUE
ARG4 - struct timespec *utime WAIT:time* REQUEUE,CMP_REQUEUE:val2
ARG5 - u32 *uaddr2 REQUEUE,CMP_REQUEUE
ARG6 - int val3 CMP_REQUEUE
*/
PRINT("sys_futex ( %p, %d, %d, %p, %p )", ARG1,ARG2,ARG3,ARG4,ARG5);
PRE_REG_READ6(long, "futex",
vki_u32 *, futex, int, op, int, val,
struct timespec *, utime, vki_u32 *, uaddr2, int, val3);
PRE_MEM_READ( "futex(futex)", ARG1, sizeof(Int) );
*flags |= SfMayBlock;
switch(ARG2) {
case VKI_FUTEX_WAIT:
if (ARG4 != 0)
PRE_MEM_READ( "futex(timeout)", ARG4, sizeof(struct vki_timespec) );
break;
case VKI_FUTEX_REQUEUE:
case VKI_FUTEX_CMP_REQUEUE:
PRE_MEM_READ( "futex(futex2)", ARG5, sizeof(Int) );
break;
case VKI_FUTEX_WAKE:
case VKI_FUTEX_FD:
/* no additional pointers */
break;
default:
SET_STATUS_Failure( VKI_ENOSYS ); // some futex function we don't understand
break;
}
}
POST(sys_futex)
{
vg_assert(SUCCESS);
POST_MEM_WRITE( ARG1, sizeof(int) );
if (ARG2 == VKI_FUTEX_FD) {
if (!ML_(fd_allowed)(RES, "futex", tid, True)) {
VG_(close)(RES);
SET_STATUS_Failure( VKI_EMFILE );
} else {
if (VG_(clo_track_fds))
ML_(record_fd_open_nameless)(tid, RES);
}
}
}
/* ---------------------------------------------------------------------
epoll_* wrappers
------------------------------------------------------------------ */
PRE(sys_epoll_create)
{
PRINT("sys_epoll_create ( %d )", ARG1);
PRE_REG_READ1(long, "epoll_create", int, size);
}
POST(sys_epoll_create)
{
vg_assert(SUCCESS);
if (!ML_(fd_allowed)(RES, "epoll_create", 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_epoll_ctl)
{
static const HChar* epoll_ctl_s[3] = {
"EPOLL_CTL_ADD",
"EPOLL_CTL_DEL",
"EPOLL_CTL_MOD"
};
PRINT("sys_epoll_ctl ( %d, %s, %d, %p )",
ARG1, ( ARG2<3 ? epoll_ctl_s[ARG2] : "?" ), ARG3, ARG4);
PRE_REG_READ4(long, "epoll_ctl",
int, epfd, int, op, int, fd, struct vki_epoll_event *, event);
if (ARG2 != VKI_EPOLL_CTL_DEL)
PRE_MEM_READ( "epoll_ctl(event)", ARG4, sizeof(struct vki_epoll_event) );
}
PRE(sys_epoll_wait)
{
*flags |= SfMayBlock;
PRINT("sys_epoll_wait ( %d, %p, %d, %d )", ARG1, ARG2, ARG3, ARG4);
PRE_REG_READ4(long, "epoll_wait",
int, epfd, struct vki_epoll_event *, events,
int, maxevents, int, timeout);
PRE_MEM_WRITE( "epoll_wait(events)", ARG2, sizeof(struct vki_epoll_event)*ARG3);
}
POST(sys_epoll_wait)
{
vg_assert(SUCCESS);
if (RES > 0)
POST_MEM_WRITE( ARG2, sizeof(struct vki_epoll_event)*RES ) ;
}
/* ---------------------------------------------------------------------
tid-related wrappers
------------------------------------------------------------------ */
PRE(sys_gettid)
{
PRINT("sys_gettid ()");
PRE_REG_READ0(long, "gettid");
}
PRE(sys_set_tid_address)
{
PRINT("sys_set_tid_address ( %p )", ARG1);
PRE_REG_READ1(long, "set_tid_address", int *, tidptr);
}
//zz PRE(sys_tkill, Special)
//zz {
//zz /* int tkill(pid_t tid, int sig); */
//zz PRINT("sys_tkill ( %d, %d )", ARG1,ARG2);
//zz PRE_REG_READ2(long, "tkill", int, tid, int, sig);
//zz if (!ML_(client_signal_OK)(ARG2)) {
//zz SET_STATUS_( -VKI_EINVAL );
//zz return;
//zz }
//zz
//zz /* If we're sending SIGKILL, check to see if the target is one of
//zz our threads and handle it specially. */
//zz if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1))
//zz SET_STATUS_(0);
//zz else
//zz SET_STATUS_(VG_(do_syscall2)(SYSNO, ARG1, ARG2));
//zz
//zz if (VG_(clo_trace_signals))
//zz VG_(message)(Vg_DebugMsg, "tkill: sent signal %d to pid %d",
//zz ARG2, ARG1);
//zz // Check to see if this kill gave us a pending signal
//zz XXX FIXME VG_(poll_signals)(tid);
//zz }
PRE(sys_tgkill)
{
PRINT("sys_tgkill ( %d, %d, %d )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "tgkill", int, tgid, int, tid, int, sig);
if (!ML_(client_signal_OK)(ARG3)) {
SET_STATUS_Failure( VKI_EINVAL );
return;
}
/* If we're sending SIGKILL, check to see if the target is one of
our threads and handle it specially. */
if (ARG3 == VKI_SIGKILL && ML_(do_sigkill)(ARG2, ARG1))
SET_STATUS_Success(0);
else
SET_STATUS_from_SysRes(VG_(do_syscall3)(SYSNO, ARG1, ARG2, ARG3));
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg, "tgkill: sent signal %d to pid %d/%d",
ARG3, ARG1, ARG2);
/* Check to see if this kill gave us a pending signal */
*flags |= SfPollAfter;
}
POST(sys_tgkill)
{
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg, "tgkill: sent signal %d to pid %d/%d",
ARG3, ARG1, ARG2);
}
/* ---------------------------------------------------------------------
fadvise64* wrappers
------------------------------------------------------------------ */
PRE(sys_fadvise64)
{
PRINT("sys_fadvise64 ( %d, %lld, %lu, %d )",
ARG1, LOHI64(ARG2,ARG3), ARG4, ARG5);
PRE_REG_READ5(long, "fadvise64",
int, fd, vki_u32, offset_low, vki_u32, offset_high,
vki_size_t, len, int, advice);
}
PRE(sys_fadvise64_64)
{
PRINT("sys_fadvise64_64 ( %d, %lld, %lld, %d )",
ARG1, LOHI64(ARG2,ARG3), LOHI64(ARG4,ARG5), ARG6);
PRE_REG_READ6(long, "fadvise64_64",
int, fd, vki_u32, offset_low, vki_u32, offset_high,
vki_u32, len_low, vki_u32, len_high, int, advice);
}
/* ---------------------------------------------------------------------
io_* 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 ( %u, %p )", 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, %p, %p )",
(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, %p )", (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, %p, %p )", (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) );
}
/* ---------------------------------------------------------------------
*_mempolicy wrappers
------------------------------------------------------------------ */
PRE(sys_mbind)
{
PRINT("sys_mbind ( %p, %lu, %d, %p, %lu, %u )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
PRE_REG_READ6(long, "mbind",
unsigned long, start, unsigned long, len,
unsigned long, policy, unsigned long *, nodemask,
unsigned long, maxnode, unsigned, flags);
if (ARG1 != 0)
PRE_MEM_READ( "mbind(nodemask)", ARG4,
VG_ROUNDUP( ARG5, sizeof(UWord) ) / sizeof(UWord) );
}
PRE(sys_set_mempolicy)
{
PRINT("sys_set_mempolicy ( %d, %p, %d )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "set_mempolicy",
int, policy, unsigned long *, nodemask,
unsigned long, maxnode);
PRE_MEM_READ( "set_mempolicy(nodemask)", ARG2,
VG_ROUNDUP( ARG3, sizeof(UWord) ) / sizeof(UWord) );
}
PRE(sys_get_mempolicy)
{
PRINT("sys_get_mempolicy ( %p, %p, %d, %p, %x )", ARG1,ARG2,ARG3,ARG4,ARG5);
PRE_REG_READ5(long, "get_mempolicy",
int *, policy, unsigned long *, nodemask,
unsigned long, maxnode, unsigned long, addr,
unsigned long, flags);
if (ARG1 != 0)
PRE_MEM_WRITE( "get_mempolicy(policy)", ARG1, sizeof(Int) );
if (ARG2 != 0)
PRE_MEM_WRITE( "get_mempolicy(nodemask)", ARG2,
VG_ROUNDUP( ARG3, sizeof(UWord) * 8 ) / sizeof(UWord) );
}
POST(sys_get_mempolicy)
{
if (ARG1 != 0)
POST_MEM_WRITE( ARG1, sizeof(Int) );
if (ARG2 != 0)
POST_MEM_WRITE( ARG2, VG_ROUNDUP( ARG3, sizeof(UWord) * 8 ) / sizeof(UWord) );
}
/* ---------------------------------------------------------------------
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 ( %d, %p, %x )", 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 ( %d, %x )", ARG1,ARG2);
PRE_REG_READ2(long, "inotify_rm_watch", int, fd, int, wd);
}
/* ---------------------------------------------------------------------
mq_* wrappers
------------------------------------------------------------------ */
PRE(sys_mq_open)
{
PRINT("sys_mq_open( %p(%s), %d, %lld, %p )",
ARG1,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 ( %p(%s) )", ARG1,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 ( %d, %p, %llu, %d, %p )",
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( %d, %p, %llu, %p, %p )",
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( %d, %p )", 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( %d, %p, %p )", 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) );
}
/* ---------------------------------------------------------------------
clock_* wrappers
------------------------------------------------------------------ */
PRE(sys_clock_settime)
{
PRINT("sys_clock_settime( %d, %p )", 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( %d, %p )" , 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( %d, %p )" , 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) );
}
PRE(sys_clock_nanosleep)
{
*flags |= SfMayBlock|SfPostOnFail;
PRINT("sys_clock_nanosleep( %d, %d, %p, %p )", 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( %d, %p, %p )", 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, %d, %p, %p )", (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, %p )", (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( %p )", ARG1);
PRE_REG_READ1(long, "timer_getoverrun", vki_timer_t, timerid);
}
PRE(sys_timer_delete)
{
PRINT("sys_timer_delete( %p )", ARG1);
PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
}
/* ---------------------------------------------------------------------
capabilities wrappers
------------------------------------------------------------------ */
PRE(sys_capget)
{
PRINT("sys_capget ( %p, %p )", ARG1, ARG2 );
PRE_REG_READ2(long, "capget",
vki_cap_user_header_t, header, vki_cap_user_data_t, data);
PRE_MEM_READ( "capget(header)", ARG1,
sizeof(struct __vki_user_cap_header_struct) );
PRE_MEM_WRITE( "capget(data)", ARG2,
sizeof(struct __vki_user_cap_data_struct) );
}
POST(sys_capget)
{
if (ARG2 != (Addr)NULL)
POST_MEM_WRITE( ARG2, sizeof(struct __vki_user_cap_data_struct) );
}
PRE(sys_capset)
{
PRINT("sys_capset ( %p, %p )", ARG1, ARG2 );
PRE_REG_READ2(long, "capset",
vki_cap_user_header_t, header,
const vki_cap_user_data_t, data);
PRE_MEM_READ( "capset(header)",
ARG1, sizeof(struct __vki_user_cap_header_struct) );
PRE_MEM_READ( "capset(data)",
ARG2, sizeof(struct __vki_user_cap_data_struct) );
}
/* ---------------------------------------------------------------------
16-bit uid/gid/groups wrappers
------------------------------------------------------------------ */
PRE(sys_getuid16)
{
PRINT("sys_getuid16 ( )");
PRE_REG_READ0(long, "getuid16");
}
PRE(sys_setuid16)
{
PRINT("sys_setuid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setuid16", vki_old_uid_t, uid);
}
PRE(sys_getgid16)
{
PRINT("sys_getgid16 ( )");
PRE_REG_READ0(long, "getgid16");
}
PRE(sys_setgid16)
{
PRINT("sys_setgid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setgid16", vki_old_gid_t, gid);
}
PRE(sys_geteuid16)
{
PRINT("sys_geteuid16 ( )");
PRE_REG_READ0(long, "geteuid16");
}
PRE(sys_getegid16)
{
PRINT("sys_getegid16 ( )");
PRE_REG_READ0(long, "getegid16");
}
PRE(sys_setreuid16)
{
PRINT("setreuid16 ( 0x%x, 0x%x )", ARG1, ARG2);
PRE_REG_READ2(long, "setreuid16", vki_old_uid_t, ruid, vki_old_uid_t, euid);
}
PRE(sys_setregid16)
{
PRINT("sys_setregid16 ( %d, %d )", ARG1, ARG2);
PRE_REG_READ2(long, "setregid16", vki_old_gid_t, rgid, vki_old_gid_t, egid);
}
PRE(sys_getgroups16)
{
PRINT("sys_getgroups16 ( %d, %p )", ARG1, ARG2);
PRE_REG_READ2(long, "getgroups16", int, size, vki_old_gid_t *, list);
if (ARG1 > 0)
PRE_MEM_WRITE( "getgroups16(list)", ARG2, ARG1 * sizeof(vki_old_gid_t) );
}
POST(sys_getgroups16)
{
vg_assert(SUCCESS);
if (ARG1 > 0 && RES > 0)
POST_MEM_WRITE( ARG2, RES * sizeof(vki_old_gid_t) );
}
PRE(sys_setgroups16)
{
PRINT("sys_setgroups16 ( %llu, %p )", (ULong)ARG1, ARG2);
PRE_REG_READ2(long, "setgroups16", int, size, vki_old_gid_t *, list);
if (ARG1 > 0)
PRE_MEM_READ( "setgroups16(list)", ARG2, ARG1 * sizeof(vki_old_gid_t) );
}
/* ---------------------------------------------------------------------
*chown16 wrappers
------------------------------------------------------------------ */
PRE(sys_chown16)
{
PRINT("sys_chown16 ( %p, 0x%x, 0x%x )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "chown16",
const char *, path,
vki_old_uid_t, owner, vki_old_gid_t, group);
PRE_MEM_RASCIIZ( "chown16(path)", ARG1 );
}
PRE(sys_fchown16)
{
PRINT("sys_fchown16 ( %d, %d, %d )", ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "fchown16",
unsigned int, fd, vki_old_uid_t, owner, vki_old_gid_t, group);
}
/* ---------------------------------------------------------------------
*xattr wrappers
------------------------------------------------------------------ */
PRE(sys_setxattr)
{
*flags |= SfMayBlock;
PRINT("sys_setxattr ( %p, %p, %p, %llu, %d )",
ARG1, ARG2, ARG3, (ULong)ARG4, ARG5);
PRE_REG_READ5(long, "setxattr",
char *, path, char *, name,
void *, value, vki_size_t, size, int, flags);
PRE_MEM_RASCIIZ( "setxattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "setxattr(name)", ARG2 );
PRE_MEM_READ( "setxattr(value)", ARG3, ARG4 );
}
PRE(sys_lsetxattr)
{
*flags |= SfMayBlock;
PRINT("sys_lsetxattr ( %p, %p, %p, %llu, %d )",
ARG1, ARG2, ARG3, (ULong)ARG4, ARG5);
PRE_REG_READ5(long, "lsetxattr",
char *, path, char *, name,
void *, value, vki_size_t, size, int, flags);
PRE_MEM_RASCIIZ( "lsetxattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "lsetxattr(name)", ARG2 );
PRE_MEM_READ( "lsetxattr(value)", ARG3, ARG4 );
}
PRE(sys_fsetxattr)
{
*flags |= SfMayBlock;
PRINT("sys_fsetxattr ( %d, %p, %p, %llu, %d )",
ARG1, ARG2, ARG3, (ULong)ARG4, ARG5);
PRE_REG_READ5(long, "fsetxattr",
int, fd, char *, name, void *, value,
vki_size_t, size, int, flags);
PRE_MEM_RASCIIZ( "fsetxattr(name)", ARG2 );
PRE_MEM_READ( "fsetxattr(value)", ARG3, ARG4 );
}
PRE(sys_getxattr)
{
*flags |= SfMayBlock;
PRINT("sys_getxattr ( %p, %p, %p, %llu )", ARG1,ARG2,ARG3, (ULong)ARG4);
PRE_REG_READ4(ssize_t, "getxattr",
char *, path, char *, name, void *, value, vki_size_t, size);
PRE_MEM_RASCIIZ( "getxattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "getxattr(name)", ARG2 );
PRE_MEM_WRITE( "getxattr(value)", ARG3, ARG4 );
}
POST(sys_getxattr)
{
vg_assert(SUCCESS);
if (RES > 0 && ARG3 != (Addr)NULL) {
POST_MEM_WRITE( ARG3, RES );
}
}
PRE(sys_lgetxattr)
{
*flags |= SfMayBlock;
PRINT("sys_lgetxattr ( %p, %p, %p, %llu )", ARG1,ARG2,ARG3, (ULong)ARG4);
PRE_REG_READ4(ssize_t, "lgetxattr",
char *, path, char *, name, void *, value, vki_size_t, size);
PRE_MEM_RASCIIZ( "lgetxattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "lgetxattr(name)", ARG2 );
PRE_MEM_WRITE( "lgetxattr(value)", ARG3, ARG4 );
}
POST(sys_lgetxattr)
{
vg_assert(SUCCESS);
if (RES > 0 && ARG3 != (Addr)NULL) {
POST_MEM_WRITE( ARG3, RES );
}
}
PRE(sys_fgetxattr)
{
*flags |= SfMayBlock;
PRINT("sys_fgetxattr ( %d, %p, %p, %llu )", ARG1, ARG2, ARG3, (ULong)ARG4);
PRE_REG_READ4(ssize_t, "fgetxattr",
int, fd, char *, name, void *, value, vki_size_t, size);
PRE_MEM_RASCIIZ( "fgetxattr(name)", ARG2 );
PRE_MEM_WRITE( "fgetxattr(value)", ARG3, ARG4 );
}
POST(sys_fgetxattr)
{
if (RES > 0 && ARG3 != (Addr)NULL)
POST_MEM_WRITE( ARG3, RES );
}
PRE(sys_listxattr)
{
*flags |= SfMayBlock;
PRINT("sys_listxattr ( %p, %p, %llu )", ARG1, ARG2, (ULong)ARG3);
PRE_REG_READ3(ssize_t, "listxattr",
char *, path, char *, list, vki_size_t, size);
PRE_MEM_RASCIIZ( "listxattr(path)", ARG1 );
PRE_MEM_WRITE( "listxattr(list)", ARG2, ARG3 );
}
POST(sys_listxattr)
{
if (RES > 0 && ARG2 != (Addr)NULL)
POST_MEM_WRITE( ARG2, RES );
}
PRE(sys_llistxattr)
{
*flags |= SfMayBlock;
PRINT("sys_llistxattr ( %p, %p, %llu )", ARG1, ARG2, (ULong)ARG3);
PRE_REG_READ3(ssize_t, "llistxattr",
char *, path, char *, list, vki_size_t, size);
PRE_MEM_RASCIIZ( "llistxattr(path)", ARG1 );
PRE_MEM_WRITE( "llistxattr(list)", ARG2, ARG3 );
}
POST(sys_llistxattr)
{
if (RES > 0 && ARG2 != (Addr)NULL)
POST_MEM_WRITE( ARG2, RES );
}
PRE(sys_flistxattr)
{
*flags |= SfMayBlock;
PRINT("sys_flistxattr ( %d, %p, %llu )", ARG1, ARG2, (ULong)ARG3);
PRE_REG_READ3(ssize_t, "flistxattr",
int, fd, char *, list, vki_size_t, size);
PRE_MEM_WRITE( "flistxattr(list)", ARG2, ARG3 );
}
POST(sys_flistxattr)
{
if (RES > 0 && ARG2 != (Addr)NULL)
POST_MEM_WRITE( ARG2, RES );
}
PRE(sys_removexattr)
{
*flags |= SfMayBlock;
PRINT("sys_removexattr ( %p, %p )", ARG1, ARG2);
PRE_REG_READ2(long, "removexattr", char *, path, char *, name);
PRE_MEM_RASCIIZ( "removexattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "removexattr(name)", ARG2 );
}
PRE(sys_lremovexattr)
{
*flags |= SfMayBlock;
PRINT("sys_lremovexattr ( %p, %p )", ARG1, ARG2);
PRE_REG_READ2(long, "lremovexattr", char *, path, char *, name);
PRE_MEM_RASCIIZ( "lremovexattr(path)", ARG1 );
PRE_MEM_RASCIIZ( "lremovexattr(name)", ARG2 );
}
PRE(sys_fremovexattr)
{
*flags |= SfMayBlock;
PRINT("sys_fremovexattr ( %d, %p )", ARG1, ARG2);
PRE_REG_READ2(long, "fremovexattr", int, fd, char *, name);
PRE_MEM_RASCIIZ( "fremovexattr(name)", ARG2 );
}
/* ---------------------------------------------------------------------
sched_* wrappers
------------------------------------------------------------------ */
PRE(sys_sched_setparam)
{
PRINT("sched_setparam ( %d, %p )", 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 ( %d, %p )", 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 ( %d )", ARG1);
PRE_REG_READ1(long, "sched_getscheduler", vki_pid_t, pid);
}
PRE(sys_sched_setscheduler)
{
PRINT("sys_sched_setscheduler ( %d, %d, %p )", 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, "sys_sched_yield");
}
PRE(sys_sched_get_priority_max)
{
PRINT("sched_get_priority_max ( %d )", ARG1);
PRE_REG_READ1(long, "sched_get_priority_max", int, policy);
}
PRE(sys_sched_get_priority_min)
{
PRINT("sched_get_priority_min ( %d )", ARG1);
PRE_REG_READ1(long, "sched_get_priority_min", int, policy);
}
PRE(sys_sched_setaffinity)
{
PRINT("sched_setaffinity ( %d, %d, %p )", 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 ( %d, %d, %p )", 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);
}
/* ---------------------------------------------------------------------
miscellaneous wrappers
------------------------------------------------------------------ */
PRE(sys_munlockall)
{
*flags |= SfMayBlock;
PRINT("sys_munlockall ( )");
PRE_REG_READ0(long, "munlockall");
}
// This has different signatures for different platforms.
//
// x86: int sys_pipe(unsigned long __user *fildes);
// AMD64: long sys_pipe(int *fildes);
// ppc32: int sys_pipe(int __user *fildes);
// ppc64: int sys_pipe(int __user *fildes);
//
// The type of the argument is most important, and it is an array of 32 bit
// values in all cases. (The return type differs across platforms, but it
// is not used.) So we use 'int' as its type. This fixed bug #113230 which
// was caused by using an array of 'unsigned long's, which didn't work on
// AMD64.
PRE(sys_pipe)
{
PRINT("sys_pipe ( %p )", ARG1);
PRE_REG_READ1(int, "pipe", int *, filedes);
PRE_MEM_WRITE( "pipe(filedes)", ARG1, 2*sizeof(int) );
}
POST(sys_pipe)
{
Int *p = (Int *)ARG1;
if (!ML_(fd_allowed)(p[0], "pipe", tid, True) ||
!ML_(fd_allowed)(p[1], "pipe", tid, True)) {
VG_(close)(p[0]);
VG_(close)(p[1]);
SET_STATUS_Failure( VKI_EMFILE );
} else {
POST_MEM_WRITE( ARG1, 2*sizeof(int) );
if (VG_(clo_track_fds)) {
ML_(record_fd_open_nameless)(tid, p[0]);
ML_(record_fd_open_nameless)(tid, p[1]);
}
}
}
PRE(sys_quotactl)
{
PRINT("sys_quotactl (0x%x, %p, 0x%x, 0x%x )", 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( %d, %d, %p, %d, %p )", 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 ( %p, %p )", 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) );
}
/* ---------------------------------------------------------------------
lseek wrapper
------------------------------------------------------------------ */
PRE(sys_lseek)
{
PRINT("sys_lseek ( %d, %d, %d )", ARG1,ARG2,ARG3);
PRE_REG_READ3(vki_off_t, "lseek",
unsigned int, fd, vki_off_t, offset, unsigned int, whence);
}
/* ---------------------------------------------------------------------
sig* wrappers
------------------------------------------------------------------ */
PRE(sys_sigpending)
{
PRINT( "sys_sigpending ( %p )", ARG1 );
PRE_REG_READ1(long, "sigpending", vki_old_sigset_t *, set);
PRE_MEM_WRITE( "sigpending(set)", ARG1, sizeof(vki_old_sigset_t));
}
POST(sys_sigpending)
{
POST_MEM_WRITE( ARG1, sizeof(vki_old_sigset_t) ) ;
}
// This syscall is not used on amd64/Linux -- it only provides
// sys_rt_sigprocmask, which uses sigset_t rather than old_sigset_t.
// This wrapper is only suitable for 32-bit architectures.
// (XXX: so how is it that PRE(sys_sigpending) above doesn't need
// conditional compilation like this?)
#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux)
PRE(sys_sigprocmask)
{
vki_old_sigset_t* set;
vki_old_sigset_t* oldset;
vki_sigset_t bigger_set;
vki_sigset_t bigger_oldset;
PRINT("sys_sigprocmask ( %d, %p, %p )",ARG1,ARG2,ARG3);
PRE_REG_READ3(long, "sigprocmask",
int, how, vki_old_sigset_t *, set, vki_old_sigset_t *, oldset);
if (ARG2 != 0)
PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_old_sigset_t));
if (ARG3 != 0)
PRE_MEM_WRITE( "sigprocmask(oldset)", ARG3, sizeof(vki_old_sigset_t));
// Nb: We must convert the smaller vki_old_sigset_t params into bigger
// vki_sigset_t params.
set = (vki_old_sigset_t*)ARG2;
oldset = (vki_old_sigset_t*)ARG3;
VG_(memset)(&bigger_set, 0, sizeof(vki_sigset_t));
VG_(memset)(&bigger_oldset, 0, sizeof(vki_sigset_t));
if (set)
bigger_set.sig[0] = *(vki_old_sigset_t*)set;
SET_STATUS_from_SysRes(
VG_(do_sys_sigprocmask) ( tid, ARG1 /*how*/,
set ? &bigger_set : NULL,
oldset ? &bigger_oldset : NULL)
);
if (oldset)
*oldset = bigger_oldset.sig[0];
if (SUCCESS)
*flags |= SfPollAfter;
}
POST(sys_sigprocmask)
{
vg_assert(SUCCESS);
if (RES == 0 && ARG3 != 0)
POST_MEM_WRITE( ARG3, sizeof(vki_old_sigset_t));
}
#endif
/* ---------------------------------------------------------------------
rt_sig* wrappers
------------------------------------------------------------------ */
PRE(sys_rt_sigaction)
{
PRINT("sys_rt_sigaction ( %d, %p, %p, %d )", ARG1,ARG2,ARG3,ARG4);
PRE_REG_READ4(long, "rt_sigaction",
int, signum, const struct sigaction *, act,
struct sigaction *, oldact, vki_size_t, sigsetsize);
if (ARG2 != 0) {
struct vki_sigaction *sa = (struct vki_sigaction *)ARG2;
PRE_MEM_READ( "rt_sigaction(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
PRE_MEM_READ( "rt_sigaction(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
PRE_MEM_READ( "rt_sigaction(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
if (sa->sa_flags & VKI_SA_RESTORER)
PRE_MEM_READ( "rt_sigaction(act->sa_restorer)", (Addr)&sa->sa_restorer, sizeof(sa->sa_restorer));
}
if (ARG3 != 0)
PRE_MEM_WRITE( "rt_sigaction(oldact)", ARG3, sizeof(struct vki_sigaction));
// XXX: doesn't seem right to be calling do_sys_sigaction for
// sys_rt_sigaction... perhaps this function should be renamed
// VG_(do_sys_rt_sigaction)() --njn
SET_STATUS_from_SysRes(
VG_(do_sys_sigaction)(ARG1, (const struct vki_sigaction *)ARG2,
(struct vki_sigaction *)ARG3)
);
}
POST(sys_rt_sigaction)
{
vg_assert(SUCCESS);
if (RES == 0 && ARG3 != 0)
POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction));
}
PRE(sys_rt_sigprocmask)
{
PRINT("sys_rt_sigprocmask ( %d, %p, %p, %llu )",ARG1,ARG2,ARG3,(ULong)ARG4);
PRE_REG_READ4(long, "rt_sigprocmask",
int, how, vki_sigset_t *, set, vki_sigset_t *, oldset,
vki_size_t, sigsetsize);
if (ARG2 != 0)
PRE_MEM_READ( "rt_sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
if (ARG3 != 0)
PRE_MEM_WRITE( "rt_sigprocmask(oldset)", ARG3, sizeof(vki_sigset_t));
// Like the kernel, we fail if the sigsetsize is not exactly what we expect.
if (sizeof(vki_sigset_t) != ARG4)
SET_STATUS_Failure( VKI_EMFILE );
else {
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_rt_sigprocmask)
{
vg_assert(SUCCESS);
if (RES == 0 && ARG3 != 0)
POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t));
}
PRE(sys_rt_sigpending)
{
PRINT( "sys_rt_sigpending ( %p )", ARG1 );
PRE_REG_READ2(long, "rt_sigpending",
vki_sigset_t *, set, vki_size_t, sigsetsize);
PRE_MEM_WRITE( "rt_sigpending(set)", ARG1, sizeof(vki_sigset_t));
}
POST(sys_rt_sigpending)
{
POST_MEM_WRITE( ARG1, sizeof(vki_sigset_t) ) ;
}
PRE(sys_rt_sigtimedwait)
{
*flags |= SfMayBlock;
PRINT("sys_rt_sigtimedwait ( %p, %p, %p, %lld )",
ARG1,ARG2,ARG3,(ULong)ARG4);
PRE_REG_READ4(long, "rt_sigtimedwait",
const vki_sigset_t *, set, vki_siginfo_t *, info,
const struct timespec *, timeout, vki_size_t, sigsetsize);
if (ARG1 != 0)
PRE_MEM_READ( "rt_sigtimedwait(set)", ARG1, sizeof(vki_sigset_t));
if (ARG2 != 0)
PRE_MEM_WRITE( "rt_sigtimedwait(info)", ARG2, sizeof(vki_siginfo_t) );
if (ARG3 != 0)
PRE_MEM_READ( "rt_sigtimedwait(timeout)",
ARG3, sizeof(struct vki_timespec) );
}
POST(sys_rt_sigtimedwait)
{
if (ARG2 != 0)
POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) );
}
PRE(sys_rt_sigqueueinfo)
{
PRINT("sys_rt_sigqueueinfo(%d, %d, %p)", 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 );
}
// XXX: x86-specific? The kernel prototypes for the different archs are
// hard to decipher.
PRE(sys_rt_sigsuspend)
{
/* The C library interface to sigsuspend just takes a pointer to
a signal mask but this system call has two arguments - a pointer
to the mask and the number of bytes used by it. The kernel insists
on the size being equal to sizeof(sigset_t) however and will just
return EINVAL if it isn't.
*/
*flags |= SfMayBlock;
PRINT("sys_rt_sigsuspend ( %p, %d )", ARG1,ARG2 );
PRE_REG_READ2(int, "rt_sigsuspend", vki_sigset_t *, mask, vki_size_t, size)
if (ARG1 != (Addr)NULL) {
PRE_MEM_READ( "rt_sigsuspend(mask)", ARG1, sizeof(vki_sigset_t) );
}
}
/* ---------------------------------------------------------------------
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;
}
}
#undef PRE
#undef POST
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/