mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 10:21:20 +00:00
EPOLL_CTL_DEL invocation. Also renamed our "struct epoll_event" to "struct vki_epoll_event" as it should be called. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4014
836 lines
24 KiB
C
836 lines
24 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- 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_debuginfo.h" // Needed for pub_core_aspacemgr :(
|
|
#include "pub_core_aspacemgr.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_mallocfree.h"
|
|
#include "pub_core_tooliface.h"
|
|
#include "pub_core_options.h"
|
|
#include "pub_core_scheduler.h"
|
|
#include "pub_core_syscall.h"
|
|
|
|
#include "priv_types_n_macros.h"
|
|
#include "priv_syswrap-generic.h"
|
|
#include "priv_syswrap-linux.h"
|
|
|
|
// Run a thread from beginning to end and return the thread's
|
|
// scheduler-return-code.
|
|
VgSchedReturnCode ML_(thread_wrapper)(Word /*ThreadId*/ tidW)
|
|
{
|
|
VG_(debugLog)(1, "core_os",
|
|
"ML_(thread_wrapper)(tid=%lld): entry\n",
|
|
(ULong)tidW);
|
|
|
|
VgSchedReturnCode ret;
|
|
ThreadId tid = (ThreadId)tidW;
|
|
ThreadState* tst = VG_(get_ThreadState)(tid);
|
|
|
|
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, "core_os",
|
|
"ML_(thread_wrapper)(tid=%lld): done\n",
|
|
(ULong)tidW);
|
|
|
|
/* Return to caller, still holding the lock. */
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
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)
|
|
|
|
PRE(sys_set_tid_address)
|
|
{
|
|
PRINT("sys_set_tid_address ( %p )", ARG1);
|
|
PRE_REG_READ1(long, "set_tid_address", int *, tidptr);
|
|
}
|
|
|
|
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_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 )", ARG1);
|
|
PRE_REG_READ2(long, "umount2", char *, path, int, flags);
|
|
PRE_MEM_RASCIIZ( "umount2(path)", ARG1);
|
|
}
|
|
|
|
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
|
|
//zz #define ADJX(bit,field) \
|
|
//zz if (tx->modes & bit) \
|
|
//zz PRE_MEM_READ( "adjtimex(timex->"#field")", \
|
|
//zz (Addr)&tx->field, sizeof(tx->field))
|
|
//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_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) );
|
|
}
|
|
}
|
|
|
|
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_(is_addressable)(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, %llu )", ARG1,ARG2,ARG3,(ULong)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, %llu )",ARG1,ARG2,ARG3,(ULong)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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 ) ;
|
|
}
|
|
|
|
PRE(sys_gettid)
|
|
{
|
|
PRINT("sys_gettid ()");
|
|
PRE_REG_READ0(long, "gettid");
|
|
}
|
|
|
|
//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)
|
|
{
|
|
/* int tgkill(pid_t tgid, pid_t tid, int sig); */
|
|
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);
|
|
}
|
|
|
|
PRE(sys_fadvise64)
|
|
{
|
|
PRINT("sys_fadvise64 ( %d, %lld, %lu, %d )", ARG1,ARG2,ARG3);
|
|
PRE_REG_READ4(long, "fadvise64",
|
|
int, fd, vki_loff_t, offset, vki_size_t, len, int, advice)
|
|
}
|
|
|
|
PRE(sys_fadvise64_64)
|
|
{
|
|
PRINT("sys_fadvise64_64 ( %d, %lld, %lld, %d )", ARG1,ARG2,ARG3);
|
|
PRE_REG_READ4(long, "fadvise64_64",
|
|
int, fd, vki_loff_t, offset, vki_loff_t, len, int, advice)
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
SizeT size;
|
|
Addr addr;
|
|
|
|
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) );
|
|
|
|
size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) +
|
|
ARG1*sizeof(struct vki_io_event));
|
|
addr = VG_(find_map_space)(0, size, True);
|
|
|
|
if (addr == 0) {
|
|
SET_STATUS_Failure( VKI_ENOMEM );
|
|
return;
|
|
}
|
|
|
|
VG_(map_segment)(addr, size, VKI_PROT_READ|VKI_PROT_WRITE, SF_FIXED);
|
|
|
|
VG_(pad_address_space)(0);
|
|
SET_STATUS_from_SysRes( VG_(do_syscall2)(SYSNO, ARG1, ARG2) );
|
|
VG_(unpad_address_space)(0);
|
|
|
|
if (SUCCESS && RES == 0) {
|
|
struct vki_aio_ring *r = *(struct vki_aio_ring **)ARG2;
|
|
|
|
vg_assert(addr == (Addr)r);
|
|
vg_assert(ML_(valid_client_addr)(addr, size, tid, "io_setup"));
|
|
|
|
VG_TRACK( new_mem_mmap, addr, size, True, True, False );
|
|
POST_MEM_WRITE( ARG2, sizeof(vki_aio_context_t) );
|
|
}
|
|
else {
|
|
VG_(unmap_range)(addr, size);
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
Segment *s = VG_(find_segment)(ARG1);
|
|
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 && s != NULL) {
|
|
VG_TRACK( die_mem_munmap, ARG1, size );
|
|
VG_(unmap_range)(ARG1, size);
|
|
}
|
|
}
|
|
|
|
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, %lld, %p )", (ULong)ARG1,(Long)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) );
|
|
}
|
|
|
|
#undef PRE
|
|
#undef POST
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|