Files
ftmemsim-valgrind/coregrind/linux/syscalls.c
Nicholas Nethercote d5717b3e8c The two patches attached resolve the exit-hang (of OOo) bug for me. The first
fixes getppid(), and the second fixes the next bug which is revealed
once getppid() does what LinuxThreads wants;  LinuxThreads uses SIGKILL
to kill off stray threads, but if we send naked SIGKILLs to Valgrind
threads, they'll die without cleaning up or informing anyone of their
death, which means that they're waited on forever. 

ADAPTED FROM CVS HEAD



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3449
2005-03-26 20:08:06 +00:00

732 lines
21 KiB
C

/*--------------------------------------------------------------------*/
/*--- Linux-specific syscalls, etc. linux/syscalls.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2005 Nicholas Nethercote
njn25@cam.ac.uk
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 "core.h"
/* ---------------------------------------------------------------------
PRE/POST wrappers for arch-generic, Linux-specific syscalls
------------------------------------------------------------------ */
// Nb: See the comment above the generic PRE/POST wrappers in
// coregrind/vg_syscalls.c for notes about how they work.
#define PRE(name, f) PRE_TEMPLATE( , vgOS_linux, name, f)
#define POST(name) POST_TEMPLATE( , vgOS_linux, name)
PRE(sys_exit_group, Special)
{
ThreadId t;
PRINT("exit_group( %d )", ARG1);
PRE_REG_READ1(void, "exit_group", int, exit_code);
/* 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 (VG_(threads)[t].status == VgTs_Empty || /* not alive */
VG_(threads)[t].os_state.threadgroup != tst->os_state.threadgroup) /* not our group */
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 */
}
/* exit_group doesn't return anything (perhaps it doesn't return?)
Nevertheless, if we don't do this, the result-not-assigned-
yet-you-said-you-were-Special assertion in the main syscall
handling logic will fire. Hence ..
*/
SET_RESULT(0);
}
PRE(sys_mount, MayBlock)
{
// 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'.
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, 0)
{
PRINT("sys_oldumount( %p )", ARG1);
PRE_REG_READ1(long, "umount", char *, path);
PRE_MEM_RASCIIZ( "umount(path)", ARG1);
}
PRE(sys_umount, 0)
{
PRINT("sys_umount( %p )", ARG1);
PRE_REG_READ2(long, "umount2", char *, path, int, flags);
PRE_MEM_RASCIIZ( "umount2(path)", ARG1);
}
PRE(sys_llseek, 0)
{
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)
{
if (RES == 0)
POST_MEM_WRITE( ARG4, sizeof(vki_loff_t) );
}
PRE(sys_adjtimex, 0)
{
struct vki_timex *tx = (struct vki_timex *)ARG1;
PRINT("sys_adjtimex ( %p )", ARG1);
PRE_REG_READ1(long, "adjtimex", struct timex *, buf);
PRE_MEM_READ( "adjtimex(timex->modes)", ARG1, sizeof(tx->modes));
#define ADJX(bit,field) \
if (tx->modes & bit) \
PRE_MEM_READ( "adjtimex(timex->"#field")", \
(Addr)&tx->field, sizeof(tx->field))
ADJX(ADJ_FREQUENCY, freq);
ADJX(ADJ_MAXERROR, maxerror);
ADJX(ADJ_ESTERROR, esterror);
ADJX(ADJ_STATUS, status);
ADJX(ADJ_TIMECONST, constant);
ADJX(ADJ_TICK, tick);
#undef ADJX
PRE_MEM_WRITE( "adjtimex(timex)", ARG1, sizeof(struct vki_timex));
}
POST(sys_adjtimex)
{
POST_MEM_WRITE( ARG1, sizeof(struct vki_timex) );
}
PRE(sys_setfsuid16, 0)
{
PRINT("sys_setfsuid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setfsuid16", vki_old_uid_t, uid);
}
PRE(sys_setfsuid, 0)
{
PRINT("sys_setfsuid ( %d )", ARG1);
PRE_REG_READ1(long, "setfsuid", vki_uid_t, uid);
}
PRE(sys_setfsgid16, 0)
{
PRINT("sys_setfsgid16 ( %d )", ARG1);
PRE_REG_READ1(long, "setfsgid16", vki_old_gid_t, gid);
}
PRE(sys_setfsgid, 0)
{
PRINT("sys_setfsgid ( %d )", ARG1);
PRE_REG_READ1(long, "setfsgid", vki_gid_t, gid);
}
PRE(sys_setresuid16, 0)
{
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, 0)
{
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, 0)
{
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)
{
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, 0)
{
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)
{
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, 0)
{
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, 0)
{
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, 0)
{
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)
{
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, 0)
{
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)
{
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, 0)
{
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, MayBlock)
{
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, 0)
{
PRINT("sys_vhangup ( )");
PRE_REG_READ0(long, "vhangup");
}
PRE(sys_sysinfo, 0)
{
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, 0)
{
PRINT("sys_personality ( %llu )", (ULong)ARG1);
PRE_REG_READ1(long, "personality", vki_u_long, persona);
}
PRE(sys_sysctl, 0)
{
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_RESULT( -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, *args->oldlenp);
}
}
PRE(sys_prctl, MayBlock)
{
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, MayBlock)
{
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)
{
POST_MEM_WRITE( ARG3, sizeof( vki_off_t ) );
}
PRE(sys_sendfile64, MayBlock)
{
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, MayBlock)
{
/*
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) );
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_RESULT(-VKI_ENOSYS); // some futex function we don't understand
break;
}
}
POST(sys_futex)
{
POST_MEM_WRITE( ARG1, sizeof(int) );
if (ARG2 == VKI_FUTEX_FD) {
if (!VG_(fd_allowed)(RES, "futex", tid, True)) {
VG_(close)(RES);
SET_RESULT( -VKI_EMFILE );
} else {
if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, RES, VG_(arena_strdup)(VG_AR_CORE, (Char*)ARG1));
}
}
}
PRE(sys_epoll_create, 0)
{
PRINT("sys_epoll_create ( %d )", ARG1);
PRE_REG_READ1(long, "epoll_create", int, size);
}
POST(sys_epoll_create)
{
if (!VG_(fd_allowed)(RES, "epoll_create", tid, True)) {
VG_(close)(RES);
SET_RESULT( -VKI_EMFILE );
} else {
if (VG_(clo_track_fds))
VG_(record_fd_open) (tid, RES, NULL);
}
}
PRE(sys_epoll_ctl, 0)
{
static const char* 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 epoll_event *, event);
PRE_MEM_READ( "epoll_ctl(event)", ARG4, sizeof(struct epoll_event) );
}
PRE(sys_epoll_wait, MayBlock)
{
PRINT("sys_epoll_wait ( %d, %p, %d, %d )", ARG1, ARG2, ARG3, ARG4);
PRE_REG_READ4(long, "epoll_wait",
int, epfd, struct epoll_event *, events,
int, maxevents, int, timeout);
PRE_MEM_WRITE( "epoll_wait(events)", ARG2, sizeof(struct epoll_event)*ARG3);
}
POST(sys_epoll_wait)
{
if (RES > 0)
POST_MEM_WRITE( ARG2, sizeof(struct epoll_event)*RES ) ;
}
PRE(sys_tkill, Special)
{
/* int tkill(pid_t tid, int sig); */
PRINT("sys_tkill ( %d, %d )", ARG1,ARG2);
PRE_REG_READ2(long, "tkill", int, tid, int, sig);
if (!VG_(client_signal_OK)(ARG2)) {
SET_RESULT( -VKI_EINVAL );
return;
}
/* If we're sending SIGKILL, check to see if the target is one of
our threads and handle it specially. */
if (ARG2 == VKI_SIGKILL && VG_(do_sigkill)(ARG1, -1))
SET_RESULT(0);
else
SET_RESULT(VG_(do_syscall2)(SYSNO, ARG1, ARG2));
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg, "tkill: sent signal %d to pid %d",
ARG2, ARG1);
// Check to see if this kill gave us a pending signal
VG_(poll_signals)(tid);
}
PRE(sys_tgkill, Special)
{
/* 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 (!VG_(client_signal_OK)(ARG3)) {
SET_RESULT( -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 && VG_(do_sigkill)(ARG2, ARG1))
SET_RESULT(0);
else
SET_RESULT(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
VG_(poll_signals)(tid);
}
POST(sys_tgkill)
{
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
VG_(poll_signals)(tid);
}
// Nb: this wrapper is "Special" because we have 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, Special)
{
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 = PGROUNDUP(sizeof(struct vki_aio_ring) +
ARG1*sizeof(struct vki_io_event));
addr = VG_(find_map_space)(0, size, True);
if (addr == 0) {
SET_RESULT( -VKI_ENOMEM );
return;
}
VG_(map_segment)(addr, size, VKI_PROT_READ|VKI_PROT_WRITE, SF_FIXED);
VG_(pad_address_space)(0);
SET_RESULT( VG_(do_syscall2)(SYSNO, ARG1, ARG2) );
VG_(unpad_address_space)(0);
if (RES == 0) {
struct vki_aio_ring *r = *(struct vki_aio_ring **)ARG2;
vg_assert(addr == (Addr)r);
vg_assert(VG_(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, Special)
{
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 = PGROUNDUP(sizeof(struct vki_aio_ring) +
r->nr*sizeof(struct vki_io_event));
SET_RESULT( VG_(do_syscall1)(SYSNO, ARG1) );
if (RES == 0 && s != NULL) {
VG_TRACK( die_mem_munmap, ARG1, size );
VG_(unmap_range)(ARG1, size);
}
}
PRE(sys_io_getevents, MayBlock)
{
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;
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, 0)
{
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, 0)
{
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 ---*/
/*--------------------------------------------------------------------*/