mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
13633 lines
492 KiB
C
13633 lines
492 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Linux-specific syscalls, etc. syswrap-linux.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2000-2017 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
#if defined(VGO_linux)
|
|
|
|
#include "pub_core_basics.h"
|
|
#include "pub_core_vki.h"
|
|
#include "pub_core_vkiscnums.h"
|
|
#include "pub_core_threadstate.h"
|
|
#include "pub_core_aspacemgr.h"
|
|
#include "pub_core_debuginfo.h" // VG_(di_notify_*)
|
|
#include "pub_core_transtab.h" // VG_(discard_translations)
|
|
#include "pub_core_xarray.h"
|
|
#include "pub_core_clientstate.h"
|
|
#include "pub_core_debuglog.h"
|
|
#include "pub_core_libcbase.h"
|
|
#include "pub_core_libcassert.h"
|
|
#include "pub_core_libcfile.h"
|
|
#include "pub_core_libcprint.h"
|
|
#include "pub_core_libcproc.h"
|
|
#include "pub_core_libcsignal.h"
|
|
#include "pub_core_machine.h" // VG_(get_SP)
|
|
#include "pub_core_mallocfree.h"
|
|
#include "pub_core_tooliface.h"
|
|
#include "pub_core_options.h"
|
|
#include "pub_core_scheduler.h"
|
|
#include "pub_core_signals.h"
|
|
#include "pub_core_stacks.h"
|
|
#include "pub_core_syscall.h"
|
|
#include "pub_core_syswrap.h"
|
|
#include "pub_core_inner.h"
|
|
#if defined(ENABLE_INNER_CLIENT_REQUEST)
|
|
#include "pub_core_clreq.h"
|
|
#endif
|
|
|
|
#include "priv_types_n_macros.h"
|
|
#include "priv_syswrap-generic.h"
|
|
#include "priv_syswrap-linux.h"
|
|
#include "priv_syswrap-main.h"
|
|
#include "priv_syswrap-xen.h"
|
|
|
|
// Run a thread from beginning to end and return the thread's
|
|
// scheduler-return-code.
|
|
static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
|
|
{
|
|
VgSchedReturnCode ret;
|
|
ThreadId tid = (ThreadId)tidW;
|
|
Int lwpid = VG_(gettid)();
|
|
ThreadState* tst = VG_(get_ThreadState)(tid);
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"thread_wrapper(tid=%u,lwpid=%d): entry\n",
|
|
tid, lwpid);
|
|
|
|
vg_assert(tst->status == VgTs_Init);
|
|
|
|
/* make sure we get the CPU lock before doing anything significant */
|
|
VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)");
|
|
|
|
if (0)
|
|
VG_(printf)("thread tid %u started: stack = %p\n",
|
|
tid, (void *)&tid);
|
|
|
|
/* Make sure error reporting is enabled in the new thread. */
|
|
tst->err_disablement_level = 0;
|
|
|
|
VG_TRACK(pre_thread_first_insn, tid);
|
|
|
|
tst->os_state.lwpid = lwpid;
|
|
/* Set the threadgroup for real. This overwrites the provisional value set
|
|
in do_clone(). See comments in do_clone for background, also #226116. */
|
|
tst->os_state.threadgroup = VG_(getpid)();
|
|
|
|
/* Thread created with all signals blocked; scheduler will set the
|
|
appropriate mask */
|
|
|
|
ret = VG_(scheduler)(tid);
|
|
|
|
vg_assert(VG_(is_exiting)(tid));
|
|
|
|
vg_assert(tst->status == VgTs_Runnable);
|
|
vg_assert(VG_(is_running_thread)(tid));
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"thread_wrapper(tid=%u,lwpid=%d): exit, schedreturncode %s\n",
|
|
tid, lwpid, VG_(name_of_VgSchedReturnCode)(ret));
|
|
|
|
/* Return to caller, still holding the lock. */
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
clone-related stuff
|
|
------------------------------------------------------------------ */
|
|
|
|
/* Run a thread all the way to the end, then do appropriate exit actions
|
|
(this is the last-one-out-turn-off-the-lights bit). */
|
|
static void run_a_thread_NORETURN ( Word tidW )
|
|
{
|
|
ThreadId tid = (ThreadId)tidW;
|
|
VgSchedReturnCode src;
|
|
Int c;
|
|
ThreadState* tst;
|
|
#ifdef ENABLE_INNER_CLIENT_REQUEST
|
|
Int registered_vgstack_id;
|
|
#endif
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"run_a_thread_NORETURN(tid=%u): pre-thread_wrapper\n",
|
|
tid);
|
|
|
|
tst = VG_(get_ThreadState)(tid);
|
|
vg_assert(tst);
|
|
|
|
/* An thread has two stacks:
|
|
* the simulated stack (used by the synthetic cpu. Guest process
|
|
is using this stack).
|
|
* the valgrind stack (used by the real cpu. Valgrind code is running
|
|
on this stack).
|
|
When Valgrind runs as an inner, it must signals that its (real) stack
|
|
is the stack to use by the outer to e.g. do stacktraces.
|
|
*/
|
|
INNER_REQUEST
|
|
(registered_vgstack_id
|
|
= VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base,
|
|
tst->os_state.valgrind_stack_init_SP));
|
|
|
|
/* Run the thread all the way through. */
|
|
src = thread_wrapper(tid);
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"run_a_thread_NORETURN(tid=%u): post-thread_wrapper\n",
|
|
tid);
|
|
|
|
c = VG_(count_living_threads)();
|
|
vg_assert(c >= 1); /* stay sane */
|
|
|
|
/* Deregister thread's stack. */
|
|
if (tst->os_state.stk_id != NULL_STK_ID)
|
|
VG_(deregister_stack)(tst->os_state.stk_id);
|
|
|
|
// Tell the tool this thread is exiting
|
|
VG_TRACK( pre_thread_ll_exit, tid );
|
|
|
|
/* If the thread is exiting with errors disabled, complain loudly;
|
|
doing so is bad (does the user know this has happened?) Also,
|
|
in all cases, be paranoid and clear the flag anyway so that the
|
|
thread slot is safe in this respect if later reallocated. This
|
|
should be unnecessary since the flag should be cleared when the
|
|
slot is reallocated, in thread_wrapper(). */
|
|
if (tst->err_disablement_level > 0) {
|
|
VG_(umsg)(
|
|
"WARNING: exiting thread has error reporting disabled.\n"
|
|
"WARNING: possibly as a result of some mistake in the use\n"
|
|
"WARNING: of the VALGRIND_DISABLE_ERROR_REPORTING macros.\n"
|
|
);
|
|
VG_(debugLog)(
|
|
1, "syswrap-linux",
|
|
"run_a_thread_NORETURN(tid=%u): "
|
|
"WARNING: exiting thread has err_disablement_level = %u\n",
|
|
tid, tst->err_disablement_level
|
|
);
|
|
}
|
|
tst->err_disablement_level = 0;
|
|
|
|
if (c == 1) {
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"run_a_thread_NORETURN(tid=%u): "
|
|
"last one standing\n",
|
|
tid);
|
|
|
|
/* We are the last one standing. Keep hold of the lock and
|
|
carry on to show final tool results, then exit the entire system.
|
|
Use the continuation pointer set at startup in m_main. */
|
|
( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src);
|
|
} else {
|
|
|
|
VG_(debugLog)(1, "syswrap-linux",
|
|
"run_a_thread_NORETURN(tid=%u): "
|
|
"not last one standing\n",
|
|
tid);
|
|
|
|
/* OK, thread is dead, but others still exist. Just exit. */
|
|
|
|
/* This releases the run lock */
|
|
VG_(exit_thread)(tid);
|
|
vg_assert(tst->status == VgTs_Zombie);
|
|
vg_assert(sizeof(tst->status) == 4);
|
|
vg_assert(sizeof(tst->os_state.exitcode) == sizeof(Word));
|
|
|
|
INNER_REQUEST (VALGRIND_STACK_DEREGISTER (registered_vgstack_id));
|
|
|
|
/* We have to use this sequence to terminate the thread to
|
|
prevent a subtle race. If VG_(exit_thread)() had left the
|
|
ThreadState as Empty, then it could have been reallocated,
|
|
reusing the stack while we're doing these last cleanups.
|
|
Instead, VG_(exit_thread) leaves it as Zombie to prevent
|
|
reallocation. We need to make sure we don't touch the stack
|
|
between marking it Empty and exiting. Hence the
|
|
assembler. */
|
|
#if defined(VGP_x86_linux)
|
|
asm volatile (
|
|
"pushl %%ebx\n"
|
|
"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) */
|
|
"popl %%ebx\n"
|
|
: "=m" (tst->status)
|
|
: "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "eax"
|
|
);
|
|
#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)
|
|
: "rax", "rdi"
|
|
);
|
|
#elif defined(VGP_ppc32_linux) || defined(VGP_ppc64be_linux) \
|
|
|| defined(VGP_ppc64le_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)
|
|
: "r0", "r3"
|
|
);
|
|
}
|
|
#elif defined(VGP_arm_linux)
|
|
asm volatile (
|
|
"str %1, %0\n" /* set tst->status = VgTs_Empty */
|
|
"mov r7, %2\n" /* set %r7 = __NR_exit */
|
|
"ldr r0, %3\n" /* set %r0 = tst->os_state.exitcode */
|
|
"svc 0x00000000\n" /* exit(tst->os_state.exitcode) */
|
|
: "=m" (tst->status)
|
|
: "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "r0", "r7"
|
|
);
|
|
#elif defined(VGP_arm64_linux)
|
|
asm volatile (
|
|
"str %w1, %0\n" /* set tst->status = VgTs_Empty (32-bit store) */
|
|
"mov x8, %2\n" /* set %x8 = __NR_exit */
|
|
"ldr x0, %3\n" /* set %x0 = tst->os_state.exitcode */
|
|
"svc 0x00000000\n" /* exit(tst->os_state.exitcode) */
|
|
: "=m" (tst->status)
|
|
: "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "x0", "x8"
|
|
);
|
|
#elif defined(VGP_s390x_linux)
|
|
asm volatile (
|
|
"st %1, %0\n" /* set tst->status = VgTs_Empty */
|
|
"lg 2, %3\n" /* set r2 = tst->os_state.exitcode */
|
|
"svc %2\n" /* exit(tst->os_state.exitcode) */
|
|
: "=m" (tst->status)
|
|
: "d" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "2"
|
|
);
|
|
#elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
|
|
asm volatile (
|
|
"sw %1, %0\n\t" /* set tst->status = VgTs_Empty */
|
|
"li $2, %2\n\t" /* set v0 = __NR_exit */
|
|
"lw $4, %3\n\t" /* set a0 = tst->os_state.exitcode */
|
|
"syscall\n\t" /* exit(tst->os_state.exitcode) */
|
|
"nop"
|
|
: "=m" (tst->status)
|
|
: "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "cc", "memory" , "v0", "a0"
|
|
);
|
|
#elif defined(VGP_nanomips_linux)
|
|
asm volatile (
|
|
"sw %1, %0 \n\t" /* set tst->status = VgTs_Empty */
|
|
"li $t4, %2 \n\t" /* set t4 = __NR_exit */
|
|
"lw $a0, %3 \n\t" /* set a0 = tst->os_state.exitcode */
|
|
"syscall[32] \n\t" /* exit(tst->os_state.exitcode) */
|
|
: "=m" (tst->status)
|
|
: "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
|
|
: "memory" , "$t4", "$a0"
|
|
);
|
|
#else
|
|
# error Unknown platform
|
|
#endif
|
|
|
|
VG_(core_panic)("Thread exit failed?\n");
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
vg_assert(0);
|
|
}
|
|
|
|
Word ML_(start_thread_NORETURN) ( void* arg )
|
|
{
|
|
ThreadState* tst = (ThreadState*)arg;
|
|
ThreadId tid = tst->tid;
|
|
|
|
run_a_thread_NORETURN ( (Word)tid );
|
|
/*NOTREACHED*/
|
|
vg_assert(0);
|
|
}
|
|
|
|
/* Allocate a stack for this thread, if it doesn't already have one.
|
|
They're allocated lazily, and never freed. Returns the initial stack
|
|
pointer value to use, or 0 if allocation failed. */
|
|
Addr ML_(allocstack)(ThreadId tid)
|
|
{
|
|
ThreadState* tst = VG_(get_ThreadState)(tid);
|
|
VgStack* stack;
|
|
Addr initial_SP;
|
|
|
|
/* Either the stack_base and stack_init_SP are both zero (in which
|
|
case a stack hasn't been allocated) or they are both non-zero,
|
|
in which case it has. */
|
|
|
|
if (tst->os_state.valgrind_stack_base == 0)
|
|
vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
|
|
|
|
if (tst->os_state.valgrind_stack_base != 0)
|
|
vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
|
|
|
|
/* If no stack is present, allocate one. */
|
|
|
|
if (tst->os_state.valgrind_stack_base == 0) {
|
|
stack = VG_(am_alloc_VgStack)( &initial_SP );
|
|
if (stack) {
|
|
tst->os_state.valgrind_stack_base = (Addr)stack;
|
|
tst->os_state.valgrind_stack_init_SP = initial_SP;
|
|
}
|
|
}
|
|
|
|
if (0)
|
|
VG_(printf)( "stack for tid %u at %p; init_SP=%p\n",
|
|
tid,
|
|
(void*)tst->os_state.valgrind_stack_base,
|
|
(void*)tst->os_state.valgrind_stack_init_SP );
|
|
|
|
return tst->os_state.valgrind_stack_init_SP;
|
|
}
|
|
|
|
/* Allocate a stack for the main thread, and run it all the way to the
|
|
end. Although we already have a working VgStack
|
|
(VG_(interim_stack)) it's better to allocate a new one, so that
|
|
overflow detection works uniformly for all threads.
|
|
*/
|
|
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(ENABLE_INNER_CLIENT_REQUEST)
|
|
{
|
|
// we must register the main thread stack before the call
|
|
// to ML_(call_on_new_stack_0_1), otherwise the outer valgrind
|
|
// reports 'write error' on the non registered stack.
|
|
ThreadState* tst = VG_(get_ThreadState)(tid);
|
|
INNER_REQUEST
|
|
((void)
|
|
VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base,
|
|
tst->os_state.valgrind_stack_init_SP));
|
|
}
|
|
#endif
|
|
|
|
#if defined(VGP_ppc32_linux)
|
|
/* make a stack frame */
|
|
sp -= 16;
|
|
sp &= ~0xF;
|
|
*(UWord *)sp = 0;
|
|
#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
|
|
/* make a stack frame */
|
|
sp -= 112;
|
|
sp &= ~((Addr)0xF);
|
|
*(UWord *)sp = 0;
|
|
#elif defined(VGP_s390x_linux)
|
|
/* make a stack frame */
|
|
sp -= 160;
|
|
sp &= ~((Addr)0xF);
|
|
*(UWord *)sp = 0;
|
|
#endif
|
|
|
|
/* If we can't even allocate the first thread's stack, we're hosed.
|
|
Give up. */
|
|
vg_assert2(sp != 0, "Cannot allocate main thread's stack.");
|
|
|
|
/* shouldn't be any other threads around yet */
|
|
vg_assert( VG_(count_living_threads)() == 1 );
|
|
|
|
ML_(call_on_new_stack_0_1)(
|
|
(Addr)sp, /* stack */
|
|
0, /* bogus return address */
|
|
run_a_thread_NORETURN, /* fn to call */
|
|
(Word)tid /* arg to give it */
|
|
);
|
|
|
|
/*NOTREACHED*/
|
|
vg_assert(0);
|
|
}
|
|
|
|
/* Clone a new thread. Note that in the clone syscalls, we hard-code
|
|
tlsaddr argument as NULL : the guest TLS is emulated via guest
|
|
registers, and Valgrind itself has no thread local storage. */
|
|
static SysRes clone_new_thread ( Word (*fn)(void *),
|
|
void* stack,
|
|
Word flags,
|
|
ThreadState* ctst,
|
|
Int* child_tidptr,
|
|
Int* parent_tidptr)
|
|
{
|
|
SysRes res;
|
|
/* Note that in all the below, we make sys_clone appear to have returned
|
|
Success(0) in the child, by assigning the relevant child guest
|
|
register(s) just before the clone syscall. */
|
|
#if defined(VGP_x86_linux)
|
|
Int eax;
|
|
ctst->arch.vex.guest_EAX = 0;
|
|
eax = do_syscall_clone_x86_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
res = VG_(mk_SysRes_x86_linux)( eax );
|
|
#elif defined(VGP_amd64_linux)
|
|
Long rax;
|
|
ctst->arch.vex.guest_RAX = 0;
|
|
rax = do_syscall_clone_amd64_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
res = VG_(mk_SysRes_amd64_linux)( rax );
|
|
#elif defined(VGP_ppc32_linux)
|
|
ULong word64;
|
|
UInt old_cr = LibVEX_GuestPPC32_get_CR( &ctst->arch.vex );
|
|
/* %r3 = 0 */
|
|
ctst->arch.vex.guest_GPR3 = 0;
|
|
/* %cr0.so = 0 */
|
|
LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
|
|
word64 = do_syscall_clone_ppc32_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
/* High half word64 is syscall return value. Low half is
|
|
the entire CR, from which we need to extract CR0.SO. */
|
|
/* VG_(printf)("word64 = 0x%llx\n", word64); */
|
|
res = VG_(mk_SysRes_ppc32_linux)(/*val*/(UInt)(word64 >> 32),
|
|
/*errflag*/ (((UInt)word64) >> 28) & 1);
|
|
#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
|
|
ULong word64;
|
|
UInt old_cr = LibVEX_GuestPPC64_get_CR( &ctst->arch.vex );
|
|
UInt flag = ctst->arch.vex.guest_syscall_flag;
|
|
/* %r3 = 0 */
|
|
ctst->arch.vex.guest_GPR3 = 0;
|
|
/* %cr0.so = 0 */
|
|
LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
|
|
word64 = do_syscall_clone_ppc64_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
/* Low half word64 is syscall return value. Hi half is
|
|
the entire CR, from which we need to extract CR0.SO. */
|
|
/* VG_(printf)("word64 = 0x%llx\n", word64); */
|
|
res = VG_(mk_SysRes_ppc64_linux)
|
|
(/*val*/(UInt)(word64 & 0xFFFFFFFFULL),
|
|
/*errflag*/ (UInt)((word64 >> (32+28)) & 1), flag);
|
|
#elif defined(VGP_s390x_linux)
|
|
ULong r2;
|
|
ctst->arch.vex.guest_r2 = 0;
|
|
r2 = do_syscall_clone_s390x_linux
|
|
(stack, flags, parent_tidptr, child_tidptr, NULL,
|
|
ML_(start_thread_NORETURN), ctst);
|
|
res = VG_(mk_SysRes_s390x_linux)( r2 );
|
|
#elif defined(VGP_arm64_linux)
|
|
ULong x0;
|
|
ctst->arch.vex.guest_X0 = 0;
|
|
x0 = do_syscall_clone_arm64_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
res = VG_(mk_SysRes_arm64_linux)( x0 );
|
|
#elif defined(VGP_arm_linux)
|
|
UInt r0;
|
|
ctst->arch.vex.guest_R0 = 0;
|
|
r0 = do_syscall_clone_arm_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
res = VG_(mk_SysRes_arm_linux)( r0 );
|
|
#elif defined(VGP_mips64_linux)
|
|
UInt ret = 0;
|
|
ctst->arch.vex.guest_r2 = 0;
|
|
ctst->arch.vex.guest_r7 = 0;
|
|
ret = do_syscall_clone_mips64_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
parent_tidptr, NULL, child_tidptr);
|
|
res = VG_(mk_SysRes_mips64_linux)( /* val */ ret, 0, /* errflag */ 0);
|
|
#elif defined(VGP_mips32_linux)
|
|
UInt ret = 0;
|
|
ctst->arch.vex.guest_r2 = 0;
|
|
ctst->arch.vex.guest_r7 = 0;
|
|
ret = do_syscall_clone_mips_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
/* High half word64 is syscall return value. Low half is
|
|
the entire CR, from which we need to extract CR0.SO. */
|
|
res = VG_ (mk_SysRes_mips32_linux) (/*val */ ret, 0, /*errflag */ 0);
|
|
#elif defined(VGP_nanomips_linux)
|
|
UInt ret = 0;
|
|
ctst->arch.vex.guest_r4 = 0;
|
|
ret = do_syscall_clone_nanomips_linux
|
|
(ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr, NULL);
|
|
res = VG_ (mk_SysRes_nanomips_linux) (ret);
|
|
#else
|
|
# error Unknown platform
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
static void setup_child ( /*OUT*/ ThreadArchState *child,
|
|
/*IN*/ ThreadArchState *parent )
|
|
{
|
|
/* We inherit our parent's guest state. */
|
|
child->vex = parent->vex;
|
|
child->vex_shadow1 = parent->vex_shadow1;
|
|
child->vex_shadow2 = parent->vex_shadow2;
|
|
|
|
#if defined(VGP_x86_linux)
|
|
extern void ML_(x86_setup_LDT_GDT) ( /*OUT*/ ThreadArchState *child,
|
|
/*IN*/ ThreadArchState *parent );
|
|
ML_(x86_setup_LDT_GDT)(child, parent);
|
|
#endif
|
|
}
|
|
|
|
static SysRes setup_child_tls (ThreadId ctid, Addr tlsaddr)
|
|
{
|
|
static const Bool debug = False;
|
|
ThreadState* ctst = VG_(get_ThreadState)(ctid);
|
|
// res is succesful by default, overriden if a real syscall is needed/done.
|
|
SysRes res = VG_(mk_SysRes_Success)(0);
|
|
|
|
if (debug)
|
|
VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
|
|
|
|
#if defined(VGP_x86_linux)
|
|
vki_modify_ldt_t* tlsinfo = (vki_modify_ldt_t*)tlsaddr;
|
|
if (debug)
|
|
VG_(printf)("clone child has SETTLS: tls info at %p: idx=%u "
|
|
"base=%#lx limit=%x; esp=%#x fs=%x gs=%x\n",
|
|
tlsinfo, tlsinfo->entry_number,
|
|
tlsinfo->base_addr, tlsinfo->limit,
|
|
ctst->arch.vex.guest_ESP,
|
|
ctst->arch.vex.guest_FS, ctst->arch.vex.guest_GS);
|
|
res = ML_(x86_sys_set_thread_area)(ctid, tlsinfo);
|
|
#elif defined(VGP_amd64_linux)
|
|
ctst->arch.vex.guest_FS_CONST = tlsaddr;
|
|
#elif defined(VGP_ppc32_linux)
|
|
ctst->arch.vex.guest_GPR2 = tlsaddr;
|
|
#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
|
|
ctst->arch.vex.guest_GPR13 = tlsaddr;
|
|
#elif defined(VGP_s390x_linux)
|
|
ctst->arch.vex.guest_a0 = (UInt) (tlsaddr >> 32);
|
|
ctst->arch.vex.guest_a1 = (UInt) tlsaddr;
|
|
#elif defined(VGP_arm64_linux)
|
|
/* Just assign the tls pointer in the guest TPIDR_EL0. */
|
|
ctst->arch.vex.guest_TPIDR_EL0 = tlsaddr;
|
|
#elif defined(VGP_arm_linux)
|
|
/* Just assign the tls pointer in the guest TPIDRURO. */
|
|
ctst->arch.vex.guest_TPIDRURO = tlsaddr;
|
|
#elif defined(VGP_mips64_linux)
|
|
ctst->arch.vex.guest_ULR = tlsaddr;
|
|
ctst->arch.vex.guest_r27 = tlsaddr;
|
|
#elif defined(VGP_mips32_linux) || defined(VGP_nanomips_linux)
|
|
ctst->arch.vex.guest_ULR = tlsaddr;
|
|
ctst->arch.vex.guest_r27 = tlsaddr;
|
|
#else
|
|
# error Unknown platform
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
When a client clones, we need to keep track of the new thread. This means:
|
|
1. allocate a ThreadId+ThreadState+stack for the thread
|
|
|
|
2. initialize the thread's new VCPU state
|
|
|
|
3. create the thread using the same args as the client requested,
|
|
but using the scheduler entrypoint for EIP, and a separate stack
|
|
for ESP.
|
|
*/
|
|
static SysRes do_clone ( ThreadId ptid,
|
|
UWord flags, Addr sp,
|
|
Int* parent_tidptr,
|
|
Int* child_tidptr,
|
|
Addr tlsaddr)
|
|
{
|
|
ThreadId ctid = VG_(alloc_ThreadState)();
|
|
ThreadState* ptst = VG_(get_ThreadState)(ptid);
|
|
ThreadState* ctst = VG_(get_ThreadState)(ctid);
|
|
UWord* stack;
|
|
SysRes res;
|
|
vki_sigset_t blockall, savedmask;
|
|
|
|
VG_(sigfillset)(&blockall);
|
|
|
|
vg_assert(VG_(is_running_thread)(ptid));
|
|
vg_assert(VG_(is_valid_tid)(ctid));
|
|
|
|
stack = (UWord*)ML_(allocstack)(ctid);
|
|
if (stack == NULL) {
|
|
res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
|
|
goto out;
|
|
}
|
|
|
|
/* Copy register state
|
|
|
|
Both parent and child return to the same place, and the code
|
|
following the clone syscall works out which is which, so we
|
|
don't need to worry about it.
|
|
|
|
The parent gets the child's new tid returned from clone, but the
|
|
child gets 0.
|
|
|
|
If the clone call specifies a NULL sp for the new thread, then
|
|
it actually gets a copy of the parent's sp.
|
|
*/
|
|
setup_child( &ctst->arch, &ptst->arch );
|
|
|
|
if (sp != 0)
|
|
VG_(set_SP)(ctid, sp);
|
|
|
|
ctst->os_state.parent = ptid;
|
|
|
|
/* inherit signal mask */
|
|
ctst->sig_mask = ptst->sig_mask;
|
|
ctst->tmp_sig_mask = ptst->sig_mask;
|
|
|
|
/* Start the child with its threadgroup being the same as the
|
|
parent's. This is so that any exit_group calls that happen
|
|
after the child is created but before it sets its
|
|
os_state.threadgroup field for real (in thread_wrapper in
|
|
syswrap-linux.c), really kill the new thread. a.k.a this avoids
|
|
a race condition in which the thread is unkillable (via
|
|
exit_group) because its threadgroup is not set. The race window
|
|
is probably only a few hundred or a few thousand cycles long.
|
|
See #226116. */
|
|
ctst->os_state.threadgroup = ptst->os_state.threadgroup;
|
|
|
|
ML_(guess_and_register_stack) (sp, ctst);
|
|
|
|
/* Assume the clone will succeed, and tell any tool that wants to
|
|
know that this thread has come into existence. We cannot defer
|
|
it beyond this point because setup_tls, just below,
|
|
causes checks to assert by making references to the new ThreadId
|
|
if we don't state the new thread exists prior to that point.
|
|
If the clone fails, we'll send out a ll_exit notification for it
|
|
at the out: label below, to clean up. */
|
|
vg_assert(VG_(owns_BigLock_LL)(ptid));
|
|
VG_TRACK ( pre_thread_ll_create, ptid, ctid );
|
|
|
|
if (flags & VKI_CLONE_SETTLS) {
|
|
res = setup_child_tls(ctid, tlsaddr);
|
|
if (sr_isError(res))
|
|
goto out;
|
|
}
|
|
flags &= ~VKI_CLONE_SETTLS;
|
|
|
|
/* start the thread with everything blocked */
|
|
VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
|
|
|
|
/* Create the new thread */
|
|
res = clone_new_thread ( ML_(start_thread_NORETURN), stack, flags, ctst,
|
|
child_tidptr, parent_tidptr);
|
|
|
|
VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
|
|
|
|
out:
|
|
if (sr_isError(res)) {
|
|
/* clone failed */
|
|
VG_(cleanup_thread)(&ctst->arch);
|
|
ctst->status = VgTs_Empty;
|
|
/* oops. Better tell the tool the thread exited in a hurry :-) */
|
|
VG_TRACK( pre_thread_ll_exit, ctid );
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/* Do a clone which is really a fork().
|
|
ML_(do_fork_clone) uses the clone syscall to fork a child process.
|
|
Note that this should not be called for a thread creation.
|
|
Also, some flags combinations are not supported, and such combinations
|
|
are handled either by masking the non supported flags or by asserting.
|
|
|
|
The CLONE_VFORK flag is accepted, as this just tells that the parent is
|
|
suspended till the child exits or calls execve. We better keep this flag,
|
|
just in case the guests parent/client code depends on this synchronisation.
|
|
|
|
We cannot keep the flag CLONE_VM, as Valgrind will do whatever host
|
|
instructions in the child process, that will mess up the parent host
|
|
memory. So, we hope for the best and assumes that the guest application does
|
|
not (really) depends on sharing the memory between parent and child in the
|
|
interval between clone and exits/execve.
|
|
|
|
If child_sp != 0, the child (guest) sp will be set to child_sp just after the
|
|
clone syscall, before child guest instructions are executed. */
|
|
static SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
|
|
Int* parent_tidptr, Int* child_tidptr,
|
|
Addr child_sp)
|
|
{
|
|
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))
|
|
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);
|
|
|
|
VG_(do_atfork_pre)(tid);
|
|
|
|
/* 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) \
|
|
|| defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
|
|
|| defined(VGP_arm_linux) || defined(VGP_mips32_linux) \
|
|
|| defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
|
|
|| defined(VGP_nanomips_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 );
|
|
#elif defined(VGP_s390x_linux)
|
|
/* Note that s390 has the stack first and then the flags */
|
|
res = VG_(do_syscall4)( __NR_clone, (UWord) NULL, flags,
|
|
(UWord)parent_tidptr, (UWord)child_tidptr);
|
|
#else
|
|
# error Unknown platform
|
|
#endif
|
|
|
|
if (!sr_isError(res) && sr_Res(res) == 0) {
|
|
/* child */
|
|
if (child_sp != 0)
|
|
VG_(set_SP)(tid, child_sp);
|
|
VG_(do_atfork_child)(tid);
|
|
|
|
/* restore signal mask */
|
|
VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
|
|
}
|
|
else
|
|
if (!sr_isError(res) && sr_Res(res) > 0) {
|
|
/* parent */
|
|
VG_(do_atfork_parent)(tid);
|
|
|
|
if (VG_(clo_trace_syscalls))
|
|
VG_(printf)(" clone(fork): process %d created child %" FMT_REGWORD "u\n",
|
|
VG_(getpid)(), (RegWord)sr_Res(res));
|
|
|
|
/* restore signal mask */
|
|
VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
PRE/POST wrappers for arch-generic, Linux-specific syscalls
|
|
------------------------------------------------------------------ */
|
|
|
|
// Nb: See the comment above the generic PRE/POST wrappers in
|
|
// m_syswrap/syswrap-generic.c for notes about how they work.
|
|
|
|
#define PRE(name) DEFN_PRE_TEMPLATE(linux, name)
|
|
#define POST(name) DEFN_POST_TEMPLATE(linux, name)
|
|
|
|
PRE(sys_clone)
|
|
{
|
|
UInt cloneflags;
|
|
Bool badarg = False;
|
|
|
|
PRINT("sys_clone ( %" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD
|
|
"x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3,
|
|
ARG4, ARG5);
|
|
|
|
// Order of arguments differs between platforms.
|
|
#if defined(VGP_x86_linux) \
|
|
|| defined(VGP_ppc32_linux) \
|
|
|| defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
|
|
|| defined(VGP_arm_linux) || defined(VGP_mips32_linux) \
|
|
|| defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
|
|
|| defined(VGP_nanomips_linux)
|
|
#define ARG_CHILD_TIDPTR ARG5
|
|
#define PRA_CHILD_TIDPTR PRA5
|
|
#define ARG_TLS ARG4
|
|
#define PRA_TLS PRA4
|
|
#elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux)
|
|
#define ARG_CHILD_TIDPTR ARG4
|
|
#define PRA_CHILD_TIDPTR PRA4
|
|
#define ARG_TLS ARG5
|
|
#define PRA_TLS PRA5
|
|
#else
|
|
# error Unknown platform
|
|
#endif
|
|
// And s390x is even more special, and inverts flags and child stack args
|
|
#if defined(VGP_s390x_linux)
|
|
#define ARG_FLAGS ARG2
|
|
#define PRA_FLAGS PRA2
|
|
#define ARG_CHILD_STACK ARG1
|
|
#define PRA_CHILD_STACK PRA1
|
|
#else
|
|
#define ARG_FLAGS ARG1
|
|
#define PRA_FLAGS PRA1
|
|
#define ARG_CHILD_STACK ARG2
|
|
#define PRA_CHILD_STACK PRA2
|
|
#endif
|
|
|
|
if (VG_(tdict).track_pre_reg_read) {
|
|
PRA_FLAGS("clone", unsigned long, flags);
|
|
PRA_CHILD_STACK("clone", void *, child_stack);
|
|
}
|
|
|
|
if (ARG_FLAGS & (VKI_CLONE_PARENT_SETTID | VKI_CLONE_PIDFD)) {
|
|
if (VG_(tdict).track_pre_reg_read) {
|
|
PRA3("clone", int *, parent_tidptr);
|
|
}
|
|
PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
|
|
if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int),
|
|
VKI_PROT_WRITE)) {
|
|
badarg = True;
|
|
}
|
|
}
|
|
if (ARG_FLAGS & VKI_CLONE_SETTLS) {
|
|
if (VG_(tdict).track_pre_reg_read) {
|
|
PRA_TLS("clone", vki_modify_ldt_t *, tlsinfo);
|
|
}
|
|
/* Not very clear what is vki_modify_ldt_t: for many platforms, it is a
|
|
dummy type (that we define as a char). We only dereference/check the
|
|
ARG_TLS pointer if the type looks like a real type, i.e. sizeof > 1. */
|
|
if (sizeof(vki_modify_ldt_t) > 1) {
|
|
PRE_MEM_READ("clone(tlsinfo)", ARG_TLS, sizeof(vki_modify_ldt_t));
|
|
if (!VG_(am_is_valid_for_client)(ARG_TLS, sizeof(vki_modify_ldt_t),
|
|
VKI_PROT_READ)) {
|
|
badarg = True;
|
|
}
|
|
}
|
|
}
|
|
if (ARG_FLAGS & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
|
|
if (VG_(tdict).track_pre_reg_read) {
|
|
PRA_CHILD_TIDPTR("clone", int *, child_tidptr);
|
|
}
|
|
PRE_MEM_WRITE("clone(child_tidptr)", ARG_CHILD_TIDPTR, sizeof(Int));
|
|
if (!VG_(am_is_valid_for_client)(ARG_CHILD_TIDPTR, sizeof(Int),
|
|
VKI_PROT_WRITE)) {
|
|
badarg = True;
|
|
}
|
|
}
|
|
|
|
if (badarg) {
|
|
SET_STATUS_Failure( VKI_EFAULT );
|
|
return;
|
|
}
|
|
|
|
cloneflags = ARG_FLAGS;
|
|
|
|
if (!ML_(client_signal_OK)(ARG_FLAGS & VKI_CSIGNAL)) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
return;
|
|
}
|
|
|
|
/* Only look at the flags we really care about */
|
|
switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
|
|
| VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
|
|
case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
|
|
/* thread creation */
|
|
SET_STATUS_from_SysRes(
|
|
do_clone(tid,
|
|
ARG_FLAGS, /* flags */
|
|
(Addr)ARG_CHILD_STACK, /* child ESP */
|
|
(Int*)(Addr)ARG3, /* parent_tidptr */
|
|
(Int*)(Addr)ARG_CHILD_TIDPTR, /* child_tidptr */
|
|
(Addr)ARG_TLS)); /* set_tls */
|
|
break;
|
|
|
|
case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
|
|
case VKI_CLONE_VFORK: /* vfork without memory sharing */
|
|
cloneflags &= ~VKI_CLONE_VM;
|
|
// FALLTHROUGH - assume vfork (somewhat) == fork, see ML_(do_fork_clone).
|
|
|
|
case 0: /* plain fork */
|
|
SET_STATUS_from_SysRes(
|
|
ML_(do_fork_clone)(tid,
|
|
cloneflags, /* flags */
|
|
(Int*)(Addr)ARG3, /* parent_tidptr */
|
|
(Int*)(Addr)ARG_CHILD_TIDPTR, /* child_tidptr */
|
|
(Addr)ARG_CHILD_STACK));
|
|
break;
|
|
|
|
default:
|
|
/* should we just ENOSYS? */
|
|
VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%" FMT_REGWORD
|
|
"x\n", ARG_FLAGS);
|
|
VG_(message)(Vg_UserMsg, "\n");
|
|
VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
|
|
VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
|
|
VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
|
|
VG_(unimplemented)
|
|
("Valgrind does not support general clone().");
|
|
}
|
|
|
|
if (SUCCESS && RES != 0) {
|
|
if (ARG_FLAGS & (VKI_CLONE_PARENT_SETTID | VKI_CLONE_PIDFD))
|
|
POST_MEM_WRITE(ARG3, sizeof(Int));
|
|
if (ARG_FLAGS & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
|
|
POST_MEM_WRITE(ARG_CHILD_TIDPTR, sizeof(Int));
|
|
if (ARG_FLAGS & VKI_CLONE_PIDFD) {
|
|
Int fd = *(Int*)(Addr)ARG3;
|
|
if (!ML_(fd_allowed)(fd, "clone", tid, True)) {
|
|
VG_(close)(fd);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless) (tid, fd);
|
|
}
|
|
}
|
|
|
|
/* Thread creation was successful; let the child have the chance
|
|
to run */
|
|
*flags |= SfYieldAfter;
|
|
}
|
|
|
|
#undef ARG_CHILD_TIDPTR
|
|
#undef PRA_CHILD_TIDPTR
|
|
#undef ARG_TLS
|
|
#undef PRA_TLS
|
|
#undef ARG_FLAGS
|
|
#undef PRA_FLAGS
|
|
#undef ARG_CHILD_STACK
|
|
#undef PRA_CHILD_STACK
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
*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( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
ARG1, (HChar*)(Addr)ARG1, ARG2, (HChar*)(Addr)ARG2, ARG3,
|
|
(HChar*)(Addr)ARG3, ARG4, ARG5);
|
|
PRE_REG_READ5(long, "mount",
|
|
char *, source, char *, target, char *, type,
|
|
unsigned long, flags, void *, data);
|
|
if (ARG1)
|
|
PRE_MEM_RASCIIZ( "mount(source)", ARG1);
|
|
PRE_MEM_RASCIIZ( "mount(target)", ARG2);
|
|
PRE_MEM_RASCIIZ( "mount(type)", ARG3);
|
|
}
|
|
|
|
PRE(sys_oldumount)
|
|
{
|
|
PRINT("sys_oldumount( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(long, "umount", char *, path);
|
|
PRE_MEM_RASCIIZ( "umount(path)", ARG1);
|
|
}
|
|
|
|
PRE(sys_umount)
|
|
{
|
|
PRINT("sys_umount( %#" FMT_REGWORD "x, %ld )", ARG1, SARG2);
|
|
PRE_REG_READ2(long, "umount2", char *, path, int, flags);
|
|
PRE_MEM_RASCIIZ( "umount2(path)", ARG1);
|
|
}
|
|
|
|
/* Not actually wrapped by GLibc but does things with the system
|
|
* mounts so it is put here.
|
|
*/
|
|
PRE(sys_pivot_root)
|
|
{
|
|
PRINT("sys_pivot_root ( %s %s )", (HChar*)(Addr)ARG1, (HChar*)(Addr)ARG2);
|
|
PRE_REG_READ2(int, "pivot_root", char *, new_root, char *, old_root);
|
|
PRE_MEM_RASCIIZ( "pivot_root(new_root)", ARG1);
|
|
PRE_MEM_RASCIIZ( "pivot_root(old_root)", ARG2);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
16- and 32-bit uid/gid wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_setfsuid16)
|
|
{
|
|
PRINT("sys_setfsuid16 ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "setfsuid16", vki_old_uid_t, uid);
|
|
}
|
|
|
|
PRE(sys_setfsuid)
|
|
{
|
|
PRINT("sys_setfsuid ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "setfsuid", vki_uid_t, uid);
|
|
}
|
|
|
|
PRE(sys_setfsgid16)
|
|
{
|
|
PRINT("sys_setfsgid16 ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "setfsgid16", vki_old_gid_t, gid);
|
|
}
|
|
|
|
PRE(sys_setfsgid)
|
|
{
|
|
PRINT("sys_setfsgid ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "setfsgid", vki_gid_t, gid);
|
|
}
|
|
|
|
PRE(sys_setresuid16)
|
|
{
|
|
PRINT("sys_setresuid16 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", 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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", ARG1,ARG2,ARG3);
|
|
PRE_REG_READ3(long, "getresuid",
|
|
vki_uid_t *, ruid, vki_uid_t *, euid, vki_uid_t *, suid);
|
|
PRE_MEM_WRITE( "getresuid(ruid)", ARG1, sizeof(vki_uid_t) );
|
|
PRE_MEM_WRITE( "getresuid(euid)", ARG2, sizeof(vki_uid_t) );
|
|
PRE_MEM_WRITE( "getresuid(suid)", ARG3, sizeof(vki_uid_t) );
|
|
}
|
|
POST(sys_getresuid)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES == 0) {
|
|
POST_MEM_WRITE( ARG1, sizeof(vki_uid_t) );
|
|
POST_MEM_WRITE( ARG2, sizeof(vki_uid_t) );
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_uid_t) );
|
|
}
|
|
}
|
|
|
|
PRE(sys_setresgid16)
|
|
{
|
|
PRINT("sys_setresgid16 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", 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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", ARG1,ARG2,ARG3);
|
|
PRE_REG_READ3(long, "getresgid",
|
|
vki_gid_t *, rgid, vki_gid_t *, egid, vki_gid_t *, sgid);
|
|
PRE_MEM_WRITE( "getresgid(rgid)", ARG1, sizeof(vki_gid_t) );
|
|
PRE_MEM_WRITE( "getresgid(egid)", ARG2, sizeof(vki_gid_t) );
|
|
PRE_MEM_WRITE( "getresgid(sgid)", ARG3, sizeof(vki_gid_t) );
|
|
}
|
|
POST(sys_getresgid)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES == 0) {
|
|
POST_MEM_WRITE( ARG1, sizeof(vki_gid_t) );
|
|
POST_MEM_WRITE( ARG2, sizeof(vki_gid_t) );
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_gid_t) );
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
miscellaneous wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_exit_group)
|
|
{
|
|
ThreadId t;
|
|
ThreadState* tst;
|
|
|
|
PRINT("exit_group( %ld )", SARG1);
|
|
PRE_REG_READ1(void, "exit_group", int, status);
|
|
|
|
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 */
|
|
/* It is unclear how one can get a threadgroup in this process which
|
|
is not the threadgroup of the calling thread:
|
|
The assignments to threadgroups are:
|
|
= 0; /// scheduler.c os_state_clear
|
|
= getpid(); /// scheduler.c in child after fork
|
|
= getpid(); /// this file, in thread_wrapper
|
|
= ptst->os_state.threadgroup; /// syswrap-*-linux.c,
|
|
copying the thread group of the thread doing clone
|
|
So, the only case where the threadgroup might be different to the getpid
|
|
value is in the child, just after fork. But then the fork syscall is
|
|
still going on, the forked thread has had no chance yet to make this
|
|
syscall. */
|
|
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;
|
|
/* Assign the exit code, VG_(nuke_all_threads_except) will assign
|
|
the exitreason. */
|
|
VG_(threads)[t].os_state.exitcode = ARG1;
|
|
}
|
|
|
|
/* Indicate in all other threads that the process is exiting.
|
|
Then wait using VG_(reap_threads) for these threads to disappear.
|
|
|
|
Can this give a deadlock if another thread is calling exit in parallel
|
|
and would then wait for this thread to disappear ?
|
|
The answer is no:
|
|
Other threads are either blocked in a syscall or have yielded the CPU.
|
|
|
|
A thread that has yielded the CPU is trying to get the big lock in
|
|
VG_(scheduler). This thread will get the CPU thanks to the call
|
|
to VG_(reap_threads). The scheduler will then check for signals,
|
|
kill the process if this is a fatal signal, and otherwise prepare
|
|
the thread for handling this signal. After this preparation, if
|
|
the thread status is VG_(is_exiting), the scheduler exits the thread.
|
|
So, a thread that has yielded the CPU does not have a chance to
|
|
call exit => no deadlock for this thread.
|
|
|
|
VG_(nuke_all_threads_except) will send the VG_SIGVGKILL signal
|
|
to all threads blocked in a syscall.
|
|
The syscall will be interrupted, and the control will go to the
|
|
scheduler. The scheduler will then return, as the thread is in
|
|
exiting state. */
|
|
|
|
VG_(nuke_all_threads_except)( tid, VgSrc_ExitProcess );
|
|
VG_(reap_threads)(tid);
|
|
VG_(threads)[tid].exitreason = VgSrc_ExitThread;
|
|
/* we do assign VgSrc_ExitThread and not VgSrc_ExitProcess, as this thread
|
|
is the thread calling exit_group and so its registers must be considered
|
|
as not reachable. See pub_tool_machine.h VG_(apply_to_GP_regs). */
|
|
|
|
/* We have to claim the syscall already succeeded. */
|
|
SET_STATUS_Success(0);
|
|
}
|
|
|
|
PRE(sys_llseek)
|
|
{
|
|
PRINT("sys_llseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
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);
|
|
if (!ML_(fd_allowed)(ARG1, "llseek", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
else
|
|
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) );
|
|
}
|
|
|
|
PRE(sys_adjtimex)
|
|
{
|
|
struct vki_timex *tx = (struct vki_timex *)(Addr)ARG1;
|
|
PRINT("sys_adjtimex ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(long, "adjtimex", struct timex *, buf);
|
|
|
|
if (ML_(safe_to_deref) (tx, sizeof(struct vki_timex))) {
|
|
PRE_MEM_READ( "adjtimex(timex->modes)", ARG1, sizeof(tx->modes));
|
|
|
|
#define ADJX(bits,field) \
|
|
if (tx->modes & (bits)) \
|
|
PRE_MEM_READ( "adjtimex(timex->"#field")", \
|
|
(Addr)&tx->field, sizeof(tx->field))
|
|
|
|
if (tx->modes & VKI_ADJ_ADJTIME) {
|
|
if (!(tx->modes & VKI_ADJ_OFFSET_READONLY))
|
|
PRE_MEM_READ( "adjtimex(timex->offset)", (Addr)&tx->offset, sizeof(tx->offset));
|
|
} else {
|
|
ADJX(VKI_ADJ_OFFSET, offset);
|
|
ADJX(VKI_ADJ_FREQUENCY, freq);
|
|
ADJX(VKI_ADJ_MAXERROR, maxerror);
|
|
ADJX(VKI_ADJ_ESTERROR, esterror);
|
|
ADJX(VKI_ADJ_STATUS, status);
|
|
ADJX(VKI_ADJ_TIMECONST|VKI_ADJ_TAI, constant);
|
|
ADJX(VKI_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_clock_adjtime)
|
|
{
|
|
struct vki_timex *tx = (struct vki_timex *)(Addr)ARG2;
|
|
PRINT("sys_clock_adjtime ( %ld, %#" FMT_REGWORD "x )", SARG1,ARG2);
|
|
PRE_REG_READ2(long, "clock_adjtime", vki_clockid_t, id, struct timex *, buf);
|
|
PRE_MEM_READ( "clock_adjtime(timex->modes)", ARG2, sizeof(tx->modes));
|
|
|
|
if (ML_(safe_to_deref) (tx, sizeof(struct vki_timex))) {
|
|
PRE_MEM_READ( "clock_adjtime(timex->modes)", ARG2, sizeof(tx->modes));
|
|
|
|
#define ADJX(bits,field) \
|
|
if (tx->modes & (bits)) \
|
|
PRE_MEM_READ( "clock_adjtime(timex->"#field")", \
|
|
(Addr)&tx->field, sizeof(tx->field))
|
|
|
|
if (tx->modes & VKI_ADJ_ADJTIME) {
|
|
if (!(tx->modes & VKI_ADJ_OFFSET_READONLY))
|
|
PRE_MEM_READ( "clock_adjtime(timex->offset)", (Addr)&tx->offset, sizeof(tx->offset));
|
|
} else {
|
|
ADJX(VKI_ADJ_OFFSET, offset);
|
|
ADJX(VKI_ADJ_FREQUENCY, freq);
|
|
ADJX(VKI_ADJ_MAXERROR, maxerror);
|
|
ADJX(VKI_ADJ_ESTERROR, esterror);
|
|
ADJX(VKI_ADJ_STATUS, status);
|
|
ADJX(VKI_ADJ_TIMECONST|VKI_ADJ_TAI, constant);
|
|
ADJX(VKI_ADJ_TICK, tick);
|
|
}
|
|
#undef ADJX
|
|
}
|
|
|
|
PRE_MEM_WRITE( "adjtimex(timex)", ARG2, sizeof(struct vki_timex));
|
|
}
|
|
|
|
POST(sys_clock_adjtime)
|
|
{
|
|
POST_MEM_WRITE( ARG2, sizeof(struct vki_timex) );
|
|
}
|
|
|
|
PRE(sys_ioperm)
|
|
{
|
|
PRINT("sys_ioperm ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %ld )",
|
|
ARG1, ARG2, SARG3 );
|
|
PRE_REG_READ3(long, "ioperm",
|
|
unsigned long, from, unsigned long, num, int, turn_on);
|
|
}
|
|
|
|
PRE(sys_syslog)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_syslog (%ld, %#" FMT_REGWORD "x, %ld)", SARG1, ARG2, SARG3);
|
|
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 ( %#" FMT_REGWORD "x )",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 ( %#" FMT_REGWORD "x )", ARG1 );
|
|
args = (struct __vki_sysctl_args *)(Addr)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 *)(Addr)ARG1;
|
|
if (args->oldlenp != NULL) {
|
|
POST_MEM_WRITE((Addr)args->oldlenp, sizeof(*args->oldlenp));
|
|
POST_MEM_WRITE((Addr)args->oldval, 1 + *args->oldlenp);
|
|
}
|
|
}
|
|
|
|
static void pre_asciiz_str(ThreadId tid, Addr str, SizeT maxlen,
|
|
const char *attr_name)
|
|
{
|
|
const HChar *step_str = (const HChar *)str;
|
|
SizeT len;
|
|
UInt i;
|
|
|
|
/*
|
|
* The name can be up to maxlen bytes long, including the terminating null
|
|
* byte. So do not check more than maxlen bytes.
|
|
*/
|
|
if (ML_(safe_to_deref)((const HChar *)str, maxlen)) {
|
|
len = VG_(strnlen)((const HChar *)str, maxlen);
|
|
if (len < maxlen)
|
|
PRE_MEM_RASCIIZ(attr_name, str);
|
|
else
|
|
PRE_MEM_READ(attr_name, str, maxlen);
|
|
} else {
|
|
/*
|
|
* Do it the slow way, one byte at a time, while checking for terminating
|
|
* '\0'.
|
|
*/
|
|
for (i = 0; i < maxlen; i++) {
|
|
PRE_MEM_READ(attr_name, (Addr)&step_str[i], 1);
|
|
if (!ML_(safe_to_deref)(&step_str[i], 1) || step_str[i] == '\0')
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_prctl)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT( "sys_prctl ( %ld, %ld, %ld, %ld, %ld )", SARG1, SARG2, SARG3, SARG4, SARG5 );
|
|
switch (ARG1) {
|
|
case VKI_PR_SET_PDEATHSIG:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, signal);
|
|
break;
|
|
case VKI_PR_GET_PDEATHSIG:
|
|
PRE_REG_READ2(int, "prctl", int, option, int *, signal);
|
|
PRE_MEM_WRITE("prctl(get-death-signal)", ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_GET_DUMPABLE:
|
|
PRE_REG_READ1(int, "prctl", int, option);
|
|
break;
|
|
case VKI_PR_SET_DUMPABLE:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, dump);
|
|
break;
|
|
case VKI_PR_GET_UNALIGN:
|
|
PRE_REG_READ2(int, "prctl", int, option, int *, value);
|
|
PRE_MEM_WRITE("prctl(get-unalign)", ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_SET_UNALIGN:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, value);
|
|
break;
|
|
case VKI_PR_GET_KEEPCAPS:
|
|
PRE_REG_READ1(int, "prctl", int, option);
|
|
break;
|
|
case VKI_PR_SET_KEEPCAPS:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, keepcaps);
|
|
break;
|
|
case VKI_PR_GET_FPEMU:
|
|
PRE_REG_READ2(int, "prctl", int, option, int *, value);
|
|
PRE_MEM_WRITE("prctl(get-fpemu)", ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_SET_FPEMU:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, value);
|
|
break;
|
|
case VKI_PR_GET_FPEXC:
|
|
PRE_REG_READ2(int, "prctl", int, option, int *, value);
|
|
PRE_MEM_WRITE("prctl(get-fpexc)", ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_SET_FPEXC:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, value);
|
|
break;
|
|
case VKI_PR_GET_TIMING:
|
|
PRE_REG_READ1(int, "prctl", int, option);
|
|
break;
|
|
case VKI_PR_SET_TIMING:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, timing);
|
|
break;
|
|
case VKI_PR_SET_NAME:
|
|
PRE_REG_READ2(int, "prctl", int, option, char *, name);
|
|
pre_asciiz_str(tid, ARG2, VKI_TASK_COMM_LEN, "prctl(set-name)");
|
|
break;
|
|
case VKI_PR_GET_NAME:
|
|
PRE_REG_READ2(int, "prctl", int, option, char *, name);
|
|
PRE_MEM_WRITE("prctl(get-name)", ARG2, VKI_TASK_COMM_LEN);
|
|
break;
|
|
case VKI_PR_GET_ENDIAN:
|
|
PRE_REG_READ2(int, "prctl", int, option, int *, value);
|
|
PRE_MEM_WRITE("prctl(get-endian)", ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_SET_ENDIAN:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, value);
|
|
break;
|
|
case VKI_PR_SET_PTRACER:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, ptracer_process_ID);
|
|
break;
|
|
case VKI_PR_SET_SECCOMP:
|
|
/* This is a bit feeble in that it uses |option| before checking
|
|
it, but at least both sides of the conditional check it. */
|
|
if (ARG2 == VKI_SECCOMP_MODE_FILTER) {
|
|
PRE_REG_READ3(int, "prctl", int, option, int, mode, char*, filter);
|
|
if (ARG3) {
|
|
/* Should check that ARG3 points at a valid struct sock_fprog.
|
|
Sounds complex; hence be lame. */
|
|
PRE_MEM_READ( "prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter)",
|
|
ARG3, 1 );
|
|
}
|
|
} else {
|
|
PRE_REG_READ2(int, "prctl", int, option, int, mode);
|
|
}
|
|
break;
|
|
case VKI_PR_CAPBSET_READ:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, capability);
|
|
break;
|
|
case VKI_PR_CAPBSET_DROP:
|
|
PRE_REG_READ2(int, "prctl", int, option, int, capability);
|
|
break;
|
|
default:
|
|
PRE_REG_READ5(long, "prctl",
|
|
int, option, unsigned long, arg2, unsigned long, arg3,
|
|
unsigned long, arg4, unsigned long, arg5);
|
|
break;
|
|
}
|
|
}
|
|
POST(sys_prctl)
|
|
{
|
|
switch (ARG1) {
|
|
case VKI_PR_GET_PDEATHSIG:
|
|
POST_MEM_WRITE(ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_GET_UNALIGN:
|
|
POST_MEM_WRITE(ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_GET_FPEMU:
|
|
POST_MEM_WRITE(ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_GET_FPEXC:
|
|
POST_MEM_WRITE(ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_GET_NAME:
|
|
POST_MEM_WRITE(ARG2, VKI_TASK_COMM_LEN);
|
|
break;
|
|
case VKI_PR_GET_ENDIAN:
|
|
POST_MEM_WRITE(ARG2, sizeof(Int));
|
|
break;
|
|
case VKI_PR_SET_NAME:
|
|
{
|
|
const HChar* new_name = (const HChar*) (Addr)ARG2;
|
|
if (new_name) { // Paranoia
|
|
ThreadState* tst = VG_(get_ThreadState)(tid);
|
|
SizeT new_len = VG_(strnlen)(new_name, VKI_TASK_COMM_LEN);
|
|
|
|
/* Don't bother reusing the memory. This is a rare event. */
|
|
tst->thread_name =
|
|
VG_(realloc)("syswrap.prctl", tst->thread_name, new_len + 1);
|
|
VG_(strlcpy)(tst->thread_name, new_name, new_len + 1);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
PRE(sys_sendfile)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_sendfile ( %ld, %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, SARG2, 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 ( %ld, %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, SARG2, 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) );
|
|
}
|
|
}
|
|
|
|
static void pre_read_timespec64 (ThreadId tid, const char *msg, UWord arg)
|
|
{
|
|
struct vki_timespec64 *ts64 = (void *)(Addr)arg;
|
|
PRE_MEM_READ (msg, (Addr) &ts64->tv_sec, sizeof(vki_time64_t));
|
|
PRE_MEM_READ (msg, (Addr) &ts64->tv_nsec, sizeof(vki_int32_t));
|
|
}
|
|
|
|
static void pre_read_itimerspec64 (ThreadId tid, const char *msg, UWord arg)
|
|
{
|
|
struct vki_itimerspec64 *its64 = (void *)(Addr)arg;
|
|
pre_read_timespec64 (tid, msg, (UWord) &its64->it_interval);
|
|
pre_read_timespec64 (tid, msg, (UWord) &its64->it_value);
|
|
}
|
|
|
|
static void futex_pre_helper ( ThreadId tid, SyscallArgLayout* layout,
|
|
SyscallArgs* arrghs, SyscallStatus* status,
|
|
UWord* flags, Bool is_time64 )
|
|
{
|
|
/*
|
|
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
|
|
*/
|
|
|
|
switch(ARG2 & ~(VKI_FUTEX_PRIVATE_FLAG|VKI_FUTEX_CLOCK_REALTIME)) {
|
|
case VKI_FUTEX_CMP_REQUEUE:
|
|
case VKI_FUTEX_WAKE_OP:
|
|
case VKI_FUTEX_CMP_REQUEUE_PI:
|
|
if (is_time64) {
|
|
PRE_REG_READ6(long, "futex_time64",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime, vki_u32 *, uaddr2, int, val3);
|
|
} else {
|
|
PRE_REG_READ6(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec *, utime, vki_u32 *, uaddr2, int, val3);
|
|
}
|
|
break;
|
|
case VKI_FUTEX_REQUEUE:
|
|
case VKI_FUTEX_WAIT_REQUEUE_PI:
|
|
if (is_time64) {
|
|
PRE_REG_READ5(long, "futex_time64",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime, vki_u32 *, uaddr2);
|
|
} else {
|
|
PRE_REG_READ5(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec *, utime, vki_u32 *, uaddr2);
|
|
}
|
|
break;
|
|
case VKI_FUTEX_WAIT_BITSET:
|
|
/* Check that the address at least begins in client-accessible area. */
|
|
if (!VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
|
|
SET_STATUS_Failure( VKI_EFAULT );
|
|
return;
|
|
}
|
|
if (*(vki_u32 *)(Addr)ARG1 != ARG3) {
|
|
if (is_time64) {
|
|
PRE_REG_READ4(long, "futex_time64",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime);
|
|
} else {
|
|
PRE_REG_READ4(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime);
|
|
}
|
|
} else {
|
|
/* Note argument 5 is unused, but argument 6 is used.
|
|
So we cannot just PRE_REG_READ6. Read argument 6 separately. */
|
|
if (is_time64) {
|
|
PRE_REG_READ4(long, "futex_time64",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime);
|
|
} else {
|
|
PRE_REG_READ4(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec *, utime);
|
|
}
|
|
if (VG_(tdict).track_pre_reg_read)
|
|
PRA6("futex",int,val3);
|
|
}
|
|
break;
|
|
case VKI_FUTEX_WAKE_BITSET:
|
|
PRE_REG_READ3(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val);
|
|
if (VG_(tdict).track_pre_reg_read) {
|
|
PRA6("futex", int, val3);
|
|
}
|
|
break;
|
|
case VKI_FUTEX_WAIT:
|
|
case VKI_FUTEX_LOCK_PI:
|
|
if (is_time64) {
|
|
PRE_REG_READ4(long, "futex_time64",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec64 *, utime);
|
|
} else {
|
|
PRE_REG_READ4(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val,
|
|
struct timespec *, utime);
|
|
}
|
|
break;
|
|
case VKI_FUTEX_WAKE:
|
|
case VKI_FUTEX_FD:
|
|
PRE_REG_READ3(long, "futex",
|
|
vki_u32 *, futex, int, op, int, val);
|
|
break;
|
|
case VKI_FUTEX_TRYLOCK_PI:
|
|
case VKI_FUTEX_UNLOCK_PI:
|
|
default:
|
|
PRE_REG_READ2(long, "futex", vki_u32 *, futex, int, op);
|
|
break;
|
|
}
|
|
|
|
*flags |= SfMayBlock;
|
|
if ((ARG2 & (VKI_FUTEX_PRIVATE_FLAG|VKI_FUTEX_LOCK_PI)) == (VKI_FUTEX_PRIVATE_FLAG|VKI_FUTEX_LOCK_PI)) {
|
|
*flags |= SfKernelRestart;
|
|
}
|
|
|
|
switch(ARG2 & ~(VKI_FUTEX_PRIVATE_FLAG|VKI_FUTEX_CLOCK_REALTIME)) {
|
|
case VKI_FUTEX_WAIT:
|
|
case VKI_FUTEX_LOCK_PI:
|
|
case VKI_FUTEX_WAIT_BITSET:
|
|
case VKI_FUTEX_WAIT_REQUEUE_PI:
|
|
PRE_MEM_READ( "futex(futex)", ARG1, sizeof(Int) );
|
|
if (ARG4 != 0) {
|
|
if (is_time64) {
|
|
pre_read_timespec64 (tid, "futex_time64(timeout)", ARG4);
|
|
} else {
|
|
PRE_MEM_READ( "futex(timeout)", ARG4,
|
|
sizeof(struct vki_timespec) );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VKI_FUTEX_REQUEUE:
|
|
case VKI_FUTEX_CMP_REQUEUE:
|
|
case VKI_FUTEX_CMP_REQUEUE_PI:
|
|
case VKI_FUTEX_WAKE_OP:
|
|
PRE_MEM_READ( "futex(futex)", ARG1, sizeof(Int) );
|
|
PRE_MEM_READ( "futex(futex2)", ARG5, sizeof(Int) );
|
|
break;
|
|
|
|
case VKI_FUTEX_FD:
|
|
case VKI_FUTEX_TRYLOCK_PI:
|
|
case VKI_FUTEX_UNLOCK_PI:
|
|
case VKI_FUTEX_WAKE:
|
|
case VKI_FUTEX_WAKE_BITSET:
|
|
PRE_MEM_READ( "futex(futex)", ARG1, sizeof(Int) );
|
|
break;
|
|
|
|
default:
|
|
SET_STATUS_Failure( VKI_ENOSYS ); // some futex function we don't understand
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void futex_post_helper ( ThreadId tid, SyscallArgs* arrghs,
|
|
SyscallStatus* status )
|
|
{
|
|
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_futex)
|
|
{
|
|
PRINT("sys_futex ( %#" FMT_REGWORD "x, %ld, %ld, %#" FMT_REGWORD
|
|
"x, %#" FMT_REGWORD "x )", ARG1, SARG2, SARG3, ARG4, ARG5);
|
|
futex_pre_helper (tid, layout, arrghs, status, flags, False);
|
|
}
|
|
|
|
POST(sys_futex)
|
|
{
|
|
futex_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
PRE(sys_futex_time64)
|
|
{
|
|
PRINT("sys_futex_time64 ( %#" FMT_REGWORD "x, %ld, %ld, %#" FMT_REGWORD
|
|
"x, %#" FMT_REGWORD "x )", ARG1, SARG2, SARG3, ARG4, ARG5);
|
|
futex_pre_helper (tid, layout, arrghs, status, flags, True);
|
|
}
|
|
|
|
POST(sys_futex_time64)
|
|
{
|
|
futex_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
PRE(sys_set_robust_list)
|
|
{
|
|
PRINT("sys_set_robust_list ( %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "set_robust_list",
|
|
struct vki_robust_list_head *, head, vki_size_t, len);
|
|
|
|
/* Just check the robust_list_head structure is readable - don't
|
|
try and chase the list as the kernel will only read it when
|
|
the thread exits so the current contents is irrelevant. */
|
|
if (ARG1 != 0)
|
|
PRE_MEM_READ("set_robust_list(head)", ARG1, ARG2);
|
|
}
|
|
|
|
PRE(sys_get_robust_list)
|
|
{
|
|
PRINT("sys_get_robust_list ( %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "get_robust_list",
|
|
int, pid,
|
|
struct vki_robust_list_head **, head_ptr,
|
|
vki_size_t *, len_ptr);
|
|
PRE_MEM_WRITE("get_robust_list(head_ptr)",
|
|
ARG2, sizeof(struct vki_robust_list_head *));
|
|
PRE_MEM_WRITE("get_robust_list(len_ptr)",
|
|
ARG3, sizeof(struct vki_size_t *));
|
|
}
|
|
POST(sys_get_robust_list)
|
|
{
|
|
POST_MEM_WRITE(ARG2, sizeof(struct vki_robust_list_head *));
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_size_t *));
|
|
}
|
|
|
|
struct pselect_sized_sigset {
|
|
const vki_sigset_t *ss;
|
|
vki_size_t ss_len;
|
|
};
|
|
struct pselect_adjusted_sigset {
|
|
struct pselect_sized_sigset ss; /* The actual syscall arg */
|
|
vki_sigset_t adjusted_ss;
|
|
};
|
|
|
|
static void pselect6_pre_helper ( ThreadId tid, SyscallArgLayout* layout,
|
|
SyscallArgs* arrghs, SyscallStatus* status,
|
|
UWord* flags, Bool is_time64 )
|
|
{
|
|
*flags |= SfMayBlock | SfPostOnFail;
|
|
if (is_time64) {
|
|
PRE_REG_READ6(long, "pselect6_time64",
|
|
int, n, vki_fd_set *, readfds, vki_fd_set *, writefds,
|
|
vki_fd_set *, exceptfds, struct vki_timespec64 *, timeout,
|
|
void *, sig);
|
|
} else {
|
|
PRE_REG_READ6(long, "pselect6",
|
|
int, n, vki_fd_set *, readfds, vki_fd_set *, writefds,
|
|
vki_fd_set *, exceptfds, struct vki_timespec *, timeout,
|
|
void *, sig);
|
|
}
|
|
// XXX: this possibly understates how much memory is read.
|
|
if (ARG2 != 0)
|
|
PRE_MEM_READ( "pselect6(readfds)",
|
|
ARG2, ARG1/8 /* __FD_SETSIZE/8 */ );
|
|
if (ARG3 != 0)
|
|
PRE_MEM_READ( "pselect6(writefds)",
|
|
ARG3, ARG1/8 /* __FD_SETSIZE/8 */ );
|
|
if (ARG4 != 0)
|
|
PRE_MEM_READ( "pselect6(exceptfds)",
|
|
ARG4, ARG1/8 /* __FD_SETSIZE/8 */ );
|
|
if (ARG5 != 0) {
|
|
if (is_time64) {
|
|
pre_read_timespec64(tid, "pselect6_time64(timeout)", ARG5);
|
|
} else {
|
|
PRE_MEM_READ( "pselect6(timeout)", ARG5,
|
|
sizeof(struct vki_timespec) );
|
|
}
|
|
}
|
|
if (ARG6 != 0) {
|
|
const struct pselect_sized_sigset *pss =
|
|
(struct pselect_sized_sigset *)(Addr)ARG6;
|
|
PRE_MEM_READ( "pselect6(sig)", ARG6, sizeof(*pss) );
|
|
if (!ML_(safe_to_deref)(pss, sizeof(*pss))) {
|
|
ARG6 = 1; /* Something recognisable to POST() hook. */
|
|
} else {
|
|
struct pselect_adjusted_sigset *pas;
|
|
pas = VG_(malloc)("syswrap.pselect6.1", sizeof(*pas));
|
|
ARG6 = (Addr)pas;
|
|
pas->ss.ss = (void *)1;
|
|
pas->ss.ss_len = pss->ss_len;
|
|
if (pss->ss_len == sizeof(*pss->ss)) {
|
|
if (pss->ss == NULL) {
|
|
pas->ss.ss = NULL;
|
|
} else {
|
|
PRE_MEM_READ("pselect6(sig->ss)", (Addr)pss->ss, pss->ss_len);
|
|
if (ML_(safe_to_deref)(pss->ss, sizeof(*pss->ss))) {
|
|
pas->adjusted_ss = *pss->ss;
|
|
pas->ss.ss = &pas->adjusted_ss;
|
|
VG_(sanitize_client_sigmask)(&pas->adjusted_ss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_pselect6)
|
|
{
|
|
PRINT("sys_pselect6 ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
pselect6_pre_helper (tid, layout, arrghs, status, flags, False);
|
|
}
|
|
|
|
POST(sys_pselect6)
|
|
{
|
|
if (ARG6 != 0 && ARG6 != 1) {
|
|
VG_(free)((struct pselect_adjusted_sigset *)(Addr)ARG6);
|
|
}
|
|
}
|
|
|
|
PRE(sys_pselect6_time64)
|
|
{
|
|
PRINT("sys_pselect6_time64 ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
pselect6_pre_helper (tid, layout, arrghs, status, flags, True);
|
|
}
|
|
|
|
POST(sys_pselect6_time64)
|
|
{
|
|
if (ARG6 != 0 && ARG6 != 1) {
|
|
VG_(free)((struct pselect_adjusted_sigset *)(Addr)ARG6);
|
|
}
|
|
}
|
|
|
|
static void ppoll_pre_helper ( ThreadId tid, SyscallArgLayout* layout,
|
|
SyscallArgs* arrghs, SyscallStatus* status,
|
|
UWord* flags, Bool is_time64 )
|
|
{
|
|
UInt i;
|
|
struct vki_pollfd* ufds = (struct vki_pollfd *)(Addr)ARG1;
|
|
*flags |= SfMayBlock | SfPostOnFail;
|
|
PRINT("sys_ppoll ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD
|
|
"x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )\n",
|
|
ARG1, ARG2, ARG3, ARG4, ARG5);
|
|
if (is_time64) {
|
|
PRE_REG_READ5(long, "ppoll_time64",
|
|
struct vki_pollfd *, ufds, unsigned int, nfds,
|
|
struct vki_timespec64 *, tsp, vki_sigset_t *, sigmask,
|
|
vki_size_t, sigsetsize);
|
|
} else {
|
|
PRE_REG_READ5(long, "ppoll",
|
|
struct vki_pollfd *, ufds, unsigned int, nfds,
|
|
struct vki_timespec *, tsp, vki_sigset_t *, sigmask,
|
|
vki_size_t, sigsetsize);
|
|
}
|
|
|
|
for (i = 0; i < ARG2; i++) {
|
|
PRE_MEM_READ( "ppoll(ufds.fd)",
|
|
(Addr)(&ufds[i].fd), sizeof(ufds[i].fd) );
|
|
PRE_MEM_READ( "ppoll(ufds.events)",
|
|
(Addr)(&ufds[i].events), sizeof(ufds[i].events) );
|
|
PRE_MEM_WRITE( "ppoll(ufds.revents)",
|
|
(Addr)(&ufds[i].revents), sizeof(ufds[i].revents) );
|
|
}
|
|
|
|
if (ARG3) {
|
|
if (is_time64) {
|
|
pre_read_timespec64(tid, "ppoll_time64(tsp)", ARG3);
|
|
} else {
|
|
PRE_MEM_READ( "ppoll(tsp)", ARG3,
|
|
sizeof(struct vki_timespec) );
|
|
}
|
|
}
|
|
if (ARG4 != 0 && sizeof(vki_sigset_t) == ARG5) {
|
|
const vki_sigset_t *guest_sigmask = (vki_sigset_t *)(Addr)ARG4;
|
|
PRE_MEM_READ( "ppoll(sigmask)", ARG4, ARG5);
|
|
if (!ML_(safe_to_deref)(guest_sigmask, sizeof(*guest_sigmask))) {
|
|
ARG4 = 1; /* Something recognisable to POST() hook. */
|
|
} else {
|
|
vki_sigset_t *vg_sigmask =
|
|
VG_(malloc)("syswrap.ppoll.1", sizeof(*vg_sigmask));
|
|
ARG4 = (Addr)vg_sigmask;
|
|
*vg_sigmask = *guest_sigmask;
|
|
VG_(sanitize_client_sigmask)(vg_sigmask);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ppoll_post_helper ( ThreadId tid, SyscallArgs* arrghs,
|
|
SyscallStatus* status )
|
|
{
|
|
vg_assert(SUCCESS || FAILURE);
|
|
if (SUCCESS && (RES >= 0)) {
|
|
UInt i;
|
|
struct vki_pollfd* ufds = (struct vki_pollfd *)(Addr)ARG1;
|
|
for (i = 0; i < ARG2; i++)
|
|
POST_MEM_WRITE( (Addr)(&ufds[i].revents), sizeof(ufds[i].revents) );
|
|
}
|
|
if (ARG4 != 0 && ARG5 == sizeof(vki_sigset_t) && ARG4 != 1) {
|
|
VG_(free)((vki_sigset_t *) (Addr)ARG4);
|
|
}
|
|
}
|
|
|
|
PRE(sys_ppoll)
|
|
{
|
|
PRINT("sys_ppoll ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD
|
|
"x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )\n",
|
|
ARG1, ARG2, ARG3, ARG4, ARG5);
|
|
ppoll_pre_helper (tid, layout, arrghs, status, flags, False);
|
|
}
|
|
|
|
POST(sys_ppoll)
|
|
{
|
|
ppoll_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
PRE(sys_ppoll_time64)
|
|
{
|
|
PRINT("sys_ppoll_time64 ( %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )\n",
|
|
ARG1, ARG2, ARG3, ARG4, ARG5);
|
|
ppoll_pre_helper (tid, layout, arrghs, status, flags, False);
|
|
}
|
|
|
|
POST(sys_ppoll_time64)
|
|
{
|
|
ppoll_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
epoll_* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_epoll_create)
|
|
{
|
|
PRINT("sys_epoll_create ( %ld )", SARG1);
|
|
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_create1)
|
|
{
|
|
PRINT("sys_epoll_create1 ( %ld )", SARG1);
|
|
PRE_REG_READ1(long, "epoll_create1", int, flags);
|
|
}
|
|
POST(sys_epoll_create1)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "epoll_create1", 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 ( %ld, %s, %ld, %#" FMT_REGWORD "x )",
|
|
SARG1, ( ARG2<3 ? epoll_ctl_s[ARG2] : "?" ), SARG3, ARG4);
|
|
PRE_REG_READ4(long, "epoll_ctl",
|
|
int, epfd, int, op, int, fd, struct vki_epoll_event *, event);
|
|
if (ARG2 != VKI_EPOLL_CTL_DEL) {
|
|
/* Just check the events field, the data field is for user space and
|
|
unused by the kernel. */
|
|
struct vki_epoll_event *event = (struct vki_epoll_event *) ARG4;
|
|
PRE_MEM_READ( "epoll_ctl(event)", (Addr) &event->events,
|
|
sizeof(__vki_u32) );
|
|
}
|
|
}
|
|
|
|
/* RES event records have been written (exclude padding). */
|
|
static void epoll_post_helper ( ThreadId tid, SyscallArgs* arrghs,
|
|
SyscallStatus* status )
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES > 0) {
|
|
Int i;
|
|
struct vki_epoll_event *events = (struct vki_epoll_event*)(Addr)ARG2;
|
|
for (i = 0; i < RES; i++) {
|
|
/* Assume both events and data are set (data is user space only). */
|
|
POST_FIELD_WRITE(events[i].events);
|
|
POST_FIELD_WRITE(events[i].data);
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_epoll_wait)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_epoll_wait ( %ld, %#" FMT_REGWORD "x, %ld, %ld )",
|
|
SARG1, ARG2, SARG3, SARG4);
|
|
PRE_REG_READ4(long, "epoll_wait",
|
|
int, epfd, struct vki_epoll_event *, events,
|
|
int, maxevents, int, timeout);
|
|
/* Assume all (maxevents) events records should be (fully) writable. */
|
|
PRE_MEM_WRITE( "epoll_wait(events)", ARG2, sizeof(struct vki_epoll_event)*ARG3);
|
|
}
|
|
POST(sys_epoll_wait)
|
|
{
|
|
epoll_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
PRE(sys_epoll_pwait)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_epoll_pwait ( %ld, %#" FMT_REGWORD "x, %ld, %ld, %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, SARG3, SARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(long, "epoll_pwait",
|
|
int, epfd, struct vki_epoll_event *, events,
|
|
int, maxevents, int, timeout, vki_sigset_t *, sigmask,
|
|
vki_size_t, sigsetsize);
|
|
/* Assume all (maxevents) events records should be (fully) writable. */
|
|
PRE_MEM_WRITE( "epoll_pwait(events)", ARG2, sizeof(struct vki_epoll_event)*ARG3);
|
|
if (ARG5)
|
|
PRE_MEM_READ( "epoll_pwait(sigmask)", ARG5, sizeof(vki_sigset_t) );
|
|
}
|
|
POST(sys_epoll_pwait)
|
|
{
|
|
epoll_post_helper (tid, arrghs, status);
|
|
}
|
|
|
|
PRE(sys_eventfd)
|
|
{
|
|
PRINT("sys_eventfd ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "sys_eventfd", unsigned int, count);
|
|
}
|
|
POST(sys_eventfd)
|
|
{
|
|
if (!ML_(fd_allowed)(RES, "eventfd", 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_eventfd2)
|
|
{
|
|
PRINT("sys_eventfd2 ( %" FMT_REGWORD "u, %ld )", ARG1, SARG2);
|
|
PRE_REG_READ2(long, "sys_eventfd2", unsigned int, count, int, flags);
|
|
}
|
|
POST(sys_eventfd2)
|
|
{
|
|
if (!ML_(fd_allowed)(RES, "eventfd2", 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_fallocate)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
#if VG_WORDSIZE == 4
|
|
PRINT("sys_fallocate ( %ld, %ld, %lld, %lld )",
|
|
SARG1, SARG2, (Long)MERGE64(ARG3,ARG4), (Long)MERGE64(ARG5,ARG6));
|
|
PRE_REG_READ6(long, "fallocate",
|
|
int, fd, int, mode,
|
|
unsigned, MERGE64_FIRST(offset), unsigned, MERGE64_SECOND(offset),
|
|
unsigned, MERGE64_FIRST(len), unsigned, MERGE64_SECOND(len));
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_fallocate ( %ld, %ld, %ld, %ld )",
|
|
SARG1, SARG2, SARG3, SARG4);
|
|
PRE_REG_READ4(long, "fallocate",
|
|
int, fd, int, mode, vki_loff_t, offset, vki_loff_t, len);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
if (!ML_(fd_allowed)(ARG1, "fallocate", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
PRE(sys_prlimit64)
|
|
{
|
|
PRINT("sys_prlimit64 ( %ld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1,ARG2,ARG3,ARG4);
|
|
PRE_REG_READ4(long, "prlimit64",
|
|
vki_pid_t, pid, unsigned int, resource,
|
|
const struct rlimit64 *, new_rlim,
|
|
struct rlimit64 *, old_rlim);
|
|
if (ARG3)
|
|
PRE_MEM_READ( "rlimit64(new_rlim)", ARG3, sizeof(struct vki_rlimit64) );
|
|
if (ARG4)
|
|
PRE_MEM_WRITE( "rlimit64(old_rlim)", ARG4, sizeof(struct vki_rlimit64) );
|
|
|
|
if (ARG3 &&
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur
|
|
> ((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
else if (ARG1 == 0 || ARG1 == VG_(getpid)()) {
|
|
switch (ARG2) {
|
|
case VKI_RLIMIT_NOFILE:
|
|
SET_STATUS_Success( 0 );
|
|
if (ARG4) {
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_cur = VG_(fd_soft_limit);
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_max = VG_(fd_hard_limit);
|
|
}
|
|
if (ARG3) {
|
|
if (((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur
|
|
> VG_(fd_hard_limit) ||
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max
|
|
!= VG_(fd_hard_limit)) {
|
|
SET_STATUS_Failure( VKI_EPERM );
|
|
}
|
|
else {
|
|
VG_(fd_soft_limit) =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VKI_RLIMIT_DATA:
|
|
SET_STATUS_Success( 0 );
|
|
if (ARG4) {
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_cur =
|
|
VG_(client_rlimit_data).rlim_cur;
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_max =
|
|
VG_(client_rlimit_data).rlim_max;
|
|
}
|
|
if (ARG3) {
|
|
if (((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur
|
|
> VG_(client_rlimit_data).rlim_max ||
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max
|
|
> VG_(client_rlimit_data).rlim_max) {
|
|
SET_STATUS_Failure( VKI_EPERM );
|
|
}
|
|
else {
|
|
VG_(client_rlimit_data).rlim_cur =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur;
|
|
VG_(client_rlimit_data).rlim_max =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VKI_RLIMIT_STACK:
|
|
SET_STATUS_Success( 0 );
|
|
if (ARG4) {
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_cur =
|
|
VG_(client_rlimit_stack).rlim_cur;
|
|
((struct vki_rlimit64 *)(Addr)ARG4)->rlim_max =
|
|
VG_(client_rlimit_stack).rlim_max;
|
|
}
|
|
if (ARG3) {
|
|
if (((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur
|
|
> VG_(client_rlimit_stack).rlim_max ||
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max
|
|
> VG_(client_rlimit_stack).rlim_max) {
|
|
SET_STATUS_Failure( VKI_EPERM );
|
|
}
|
|
else {
|
|
VG_(threads)[tid].client_stack_szB =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur;
|
|
VG_(client_rlimit_stack).rlim_cur =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_cur;
|
|
VG_(client_rlimit_stack).rlim_max =
|
|
((struct vki_rlimit64 *)(Addr)ARG3)->rlim_max;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
POST(sys_prlimit64)
|
|
{
|
|
if (ARG4)
|
|
POST_MEM_WRITE( ARG4, sizeof(struct vki_rlimit64) );
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
tid-related wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_gettid)
|
|
{
|
|
PRINT("sys_gettid ()");
|
|
PRE_REG_READ0(long, "gettid");
|
|
}
|
|
|
|
PRE(sys_set_tid_address)
|
|
{
|
|
PRINT("sys_set_tid_address ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(long, "set_tid_address", int *, tidptr);
|
|
}
|
|
|
|
PRE(sys_tkill)
|
|
{
|
|
PRINT("sys_tkill ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(long, "tkill", int, tid, int, sig);
|
|
if (!ML_(client_signal_OK)(ARG2)) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
return;
|
|
}
|
|
|
|
/* Check to see if this kill gave us a pending signal */
|
|
*flags |= SfPollAfter;
|
|
|
|
if (VG_(clo_trace_signals))
|
|
VG_(message)(Vg_DebugMsg, "tkill: sending signal %ld to pid %ld\n",
|
|
SARG2, SARG1);
|
|
|
|
/* If we're sending SIGKILL, check to see if the target is one of
|
|
our threads and handle it specially. */
|
|
if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) {
|
|
SET_STATUS_Success(0);
|
|
return;
|
|
}
|
|
|
|
/* Ask to handle this syscall via the slow route, since that's the
|
|
only one that sets tst->status to VgTs_WaitSys. If the result
|
|
of doing the syscall is an immediate run of
|
|
async_signalhandler() in m_signals, then we need the thread to
|
|
be properly tidied away. I have the impression the previous
|
|
version of this wrapper worked on x86/amd64 only because the
|
|
kernel did not immediately deliver the async signal to this
|
|
thread (on ppc it did, which broke the assertion re tst->status
|
|
at the top of async_signalhandler()). */
|
|
*flags |= SfMayBlock;
|
|
}
|
|
POST(sys_tkill)
|
|
{
|
|
if (VG_(clo_trace_signals))
|
|
VG_(message)(Vg_DebugMsg, "tkill: sent signal %ld to pid %ld\n",
|
|
SARG2, SARG1);
|
|
}
|
|
|
|
PRE(sys_tgkill)
|
|
{
|
|
PRINT("sys_tgkill ( %ld, %ld, %ld )", SARG1, SARG2, SARG3);
|
|
PRE_REG_READ3(long, "tgkill", int, tgid, int, tid, int, sig);
|
|
if (!ML_(client_signal_OK)(ARG3)) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
return;
|
|
}
|
|
|
|
/* Check to see if this kill gave us a pending signal */
|
|
*flags |= SfPollAfter;
|
|
|
|
if (VG_(clo_trace_signals))
|
|
VG_(message)(Vg_DebugMsg,
|
|
"tgkill: sending signal %ld to pid %ld/%ld\n",
|
|
SARG3, SARG1, SARG2);
|
|
|
|
/* If we're sending SIGKILL, check to see if the target is one of
|
|
our threads and handle it specially. */
|
|
if (ARG3 == VKI_SIGKILL && ML_(do_sigkill)(ARG2, ARG1)) {
|
|
SET_STATUS_Success(0);
|
|
return;
|
|
}
|
|
|
|
/* Ask to handle this syscall via the slow route, since that's the
|
|
only one that sets tst->status to VgTs_WaitSys. If the result
|
|
of doing the syscall is an immediate run of
|
|
async_signalhandler() in m_signals, then we need the thread to
|
|
be properly tidied away. I have the impression the previous
|
|
version of this wrapper worked on x86/amd64 only because the
|
|
kernel did not immediately deliver the async signal to this
|
|
thread (on ppc it did, which broke the assertion re tst->status
|
|
at the top of async_signalhandler()). */
|
|
*flags |= SfMayBlock;
|
|
}
|
|
POST(sys_tgkill)
|
|
{
|
|
if (VG_(clo_trace_signals))
|
|
VG_(message)(Vg_DebugMsg,
|
|
"tgkill: sent signal %ld to pid %ld/%ld\n",
|
|
SARG3, SARG1, SARG2);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
fadvise64* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_fadvise64)
|
|
{
|
|
PRINT("sys_fadvise64 ( %ld, %llu, %" FMT_REGWORD "u, %ld )",
|
|
SARG1, MERGE64(ARG2,ARG3), ARG4, SARG5);
|
|
PRE_REG_READ5(long, "fadvise64",
|
|
int, fd, vki_u32, MERGE64_FIRST(offset), vki_u32, MERGE64_SECOND(offset),
|
|
vki_size_t, len, int, advice);
|
|
}
|
|
|
|
PRE(sys_fadvise64_64)
|
|
{
|
|
PRINT("sys_fadvise64_64 ( %ld, %llu, %llu, %ld )",
|
|
SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4,ARG5), SARG6);
|
|
PRE_REG_READ6(long, "fadvise64_64",
|
|
int, fd, vki_u32, MERGE64_FIRST(offset), vki_u32, MERGE64_SECOND(offset),
|
|
vki_u32, MERGE64_FIRST(len), vki_u32, MERGE64_SECOND(len), 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 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", 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 **)(Addr)ARG2;
|
|
vg_assert(ML_(valid_client_addr)((Addr)r, size, tid, "io_setup"));
|
|
|
|
ML_(notify_core_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)
|
|
{
|
|
SizeT size = 0;
|
|
|
|
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...
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG1, sizeof(struct vki_aio_ring))) {
|
|
struct vki_aio_ring *r = (struct vki_aio_ring *)(Addr)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)( (Addr)ARG1, (ULong)size,
|
|
"PRE(sys_io_destroy)" );
|
|
}
|
|
}
|
|
|
|
PRE(sys_io_getevents)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_io_getevents ( %llu, %lld, %lld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )",
|
|
(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 *)(Addr)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;
|
|
|
|
case VKI_IOCB_CMD_FSYNC:
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_FDSYNC:
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_PREADV:
|
|
if (vev->result > 0) {
|
|
struct vki_iovec * vec = (struct vki_iovec *)(Addr)cb->aio_buf;
|
|
Int remains = vev->result;
|
|
Int j;
|
|
|
|
for (j = 0; j < cb->aio_nbytes; j++) {
|
|
Int nReadThisBuf = vec[j].iov_len;
|
|
if (nReadThisBuf > remains) nReadThisBuf = remains;
|
|
POST_MEM_WRITE( (Addr)vec[j].iov_base, nReadThisBuf );
|
|
remains -= nReadThisBuf;
|
|
if (remains < 0) VG_(core_panic)("io_getevents(PREADV): remains < 0");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_PWRITEV:
|
|
break;
|
|
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,
|
|
"Warning: unhandled io_getevents opcode: %u\n",
|
|
cb->aio_lio_opcode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_io_submit)
|
|
{
|
|
Int i, j;
|
|
|
|
PRINT("sys_io_submit ( %" FMT_REGWORD "u, %ld, %#" FMT_REGWORD "x )",
|
|
ARG1, SARG2, 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 **)(Addr)ARG3)[i];
|
|
struct vki_iovec *iov;
|
|
|
|
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;
|
|
|
|
case VKI_IOCB_CMD_FSYNC:
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_FDSYNC:
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_PREADV:
|
|
iov = (struct vki_iovec *)(Addr)cb->aio_buf;
|
|
PRE_MEM_READ( "io_submit(PREADV)", cb->aio_buf, cb->aio_nbytes * sizeof(struct vki_iovec) );
|
|
for (j = 0; j < cb->aio_nbytes; j++)
|
|
PRE_MEM_WRITE( "io_submit(PREADV(iov[i]))", (Addr)iov[j].iov_base, iov[j].iov_len );
|
|
break;
|
|
|
|
case VKI_IOCB_CMD_PWRITEV:
|
|
iov = (struct vki_iovec *)(Addr)cb->aio_buf;
|
|
PRE_MEM_READ( "io_submit(PWRITEV)", cb->aio_buf, cb->aio_nbytes * sizeof(struct vki_iovec) );
|
|
for (j = 0; j < cb->aio_nbytes; j++)
|
|
PRE_MEM_READ( "io_submit(PWRITEV(iov[i]))", (Addr)iov[j].iov_base, iov[j].iov_len );
|
|
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, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
(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 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "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-1, sizeof(UWord) * 8 ) / 8 );
|
|
}
|
|
|
|
PRE(sys_set_mempolicy)
|
|
{
|
|
PRINT("sys_set_mempolicy ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, 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-1, sizeof(UWord) * 8 ) / 8 );
|
|
}
|
|
|
|
PRE(sys_get_mempolicy)
|
|
{
|
|
PRINT("sys_get_mempolicy ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "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-1, sizeof(UWord) * 8 ) / 8 );
|
|
}
|
|
POST(sys_get_mempolicy)
|
|
{
|
|
if (ARG1 != 0)
|
|
POST_MEM_WRITE( ARG1, sizeof(Int) );
|
|
if (ARG2 != 0)
|
|
POST_MEM_WRITE( ARG2, VG_ROUNDUP( ARG3-1, sizeof(UWord) * 8 ) / 8 );
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
fanotify_* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_fanotify_init)
|
|
{
|
|
PRINT("sys_fanotify_init ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2);
|
|
PRE_REG_READ2(long, "fanotify_init",
|
|
unsigned int, flags, unsigned int, event_f_flags);
|
|
}
|
|
|
|
POST(sys_fanotify_init)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "fanotify_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_fanotify_mark)
|
|
{
|
|
#if VG_WORDSIZE == 4
|
|
PRINT( "sys_fanotify_mark ( %ld, %" FMT_REGWORD "u, %llu, %ld, %#"
|
|
FMT_REGWORD "x(%s))", SARG1, ARG2, MERGE64(ARG3,ARG4), SARG5, ARG6,
|
|
(HChar *)(Addr)ARG6);
|
|
PRE_REG_READ6(long, "sys_fanotify_mark",
|
|
int, fanotify_fd, unsigned int, flags,
|
|
__vki_u32, mask0, __vki_u32, mask1,
|
|
int, dfd, const char *, pathname);
|
|
if (ARG6)
|
|
PRE_MEM_RASCIIZ( "fanotify_mark(path)", ARG6);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT( "sys_fanotify_mark ( %ld, %lu, %lu, %ld, %#lx(%s))",
|
|
SARG1, ARG2, ARG3, SARG4, ARG5, (HChar *)(Addr)ARG5);
|
|
PRE_REG_READ5(long, "sys_fanotify_mark",
|
|
int, fanotify_fd, unsigned int, flags,
|
|
__vki_u64, mask,
|
|
int, dfd, const char *, pathname);
|
|
if (ARG5)
|
|
PRE_MEM_RASCIIZ( "fanotify_mark(path)", ARG5);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
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_init1)
|
|
{
|
|
PRINT("sys_inotify_init ( %ld )", SARG1);
|
|
PRE_REG_READ1(long, "inotify_init", int, flag);
|
|
}
|
|
|
|
POST(sys_inotify_init1)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "inotify_init", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless) (tid, RES);
|
|
}
|
|
}
|
|
|
|
PRE(sys_inotify_add_watch)
|
|
{
|
|
PRINT( "sys_inotify_add_watch ( %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "inotify_add_watch", int, fd, char *, path, int, mask);
|
|
PRE_MEM_RASCIIZ( "inotify_add_watch(path)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_inotify_rm_watch)
|
|
{
|
|
PRINT( "sys_inotify_rm_watch ( %ld, %" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "inotify_rm_watch", int, fd, int, wd);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
mq_* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_mq_open)
|
|
{
|
|
PRINT("sys_mq_open( %#" FMT_REGWORD "x(%s), %ld, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x )", ARG1, (HChar*)(Addr)ARG1, SARG2, 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 *)(Addr)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, (HChar*)(Addr)ARG1);
|
|
}
|
|
}
|
|
|
|
PRE(sys_mq_unlink)
|
|
{
|
|
PRINT("sys_mq_unlink ( %#" FMT_REGWORD "x(%s) )", ARG1,(char*)(Addr)ARG1);
|
|
PRE_REG_READ1(long, "mq_unlink", const char *, name);
|
|
PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 );
|
|
}
|
|
|
|
PRE(sys_mq_timedsend)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_mq_timedsend ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1,ARG2,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_timedsend_time64)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_mq_timedsend_time64 ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1,ARG2,ARG3,ARG4,ARG5);
|
|
PRE_REG_READ5(long, "mq_timedsend_time64",
|
|
vki_mqd_t, mqdes, const char *, msg_ptr, vki_size_t, msg_len,
|
|
unsigned int, msg_prio,
|
|
const struct vki_timespec64 *, abs_timeout);
|
|
if (!ML_(fd_allowed)(ARG1, "mq_timedsend_time64", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
PRE_MEM_READ( "mq_timedsend_time64(msg_ptr)", ARG2, ARG3 );
|
|
if (ARG5 != 0)
|
|
pre_read_timespec64(tid, "mq_timedsend_time64(abs_timeout)", ARG5);
|
|
}
|
|
}
|
|
|
|
PRE(sys_mq_timedreceive)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_mq_timedreceive( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1,ARG2,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, RES );
|
|
if (ARG4 != 0)
|
|
POST_MEM_WRITE( ARG4, sizeof(unsigned int) );
|
|
}
|
|
|
|
PRE(sys_mq_timedreceive_time64)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_mq_timedreceive_time64( %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1,ARG2,ARG3,ARG4,ARG5);
|
|
PRE_REG_READ5(ssize_t, "mq_timedreceive_time64",
|
|
vki_mqd_t, mqdes, char *, msg_ptr, vki_size_t, msg_len,
|
|
unsigned int *, msg_prio,
|
|
const struct vki_timespec64 *, abs_timeout);
|
|
if (!ML_(fd_allowed)(ARG1, "mq_timedreceive_time64", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
PRE_MEM_WRITE( "mq_timedreceive_time64(msg_ptr)", ARG2, ARG3 );
|
|
if (ARG4 != 0)
|
|
PRE_MEM_WRITE( "mq_timedreceive_time64(msg_prio)",
|
|
ARG4, sizeof(unsigned int) );
|
|
if (ARG5 != 0)
|
|
pre_read_timespec64(tid, "mq_timedreceive_time64(abs_timeout)", ARG5);
|
|
}
|
|
}
|
|
|
|
POST(sys_mq_timedreceive_time64)
|
|
{
|
|
POST_MEM_WRITE( ARG2, RES );
|
|
if (ARG4 != 0)
|
|
POST_MEM_WRITE( ARG4, sizeof(unsigned int) );
|
|
}
|
|
|
|
PRE(sys_mq_notify)
|
|
{
|
|
PRINT("sys_mq_notify( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2 );
|
|
PRE_REG_READ2(long, "mq_notify",
|
|
vki_mqd_t, mqdes, const struct sigevent *, notification);
|
|
if (!ML_(fd_allowed)(ARG1, "mq_notify", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
else if (ARG2 != 0)
|
|
PRE_MEM_READ( "mq_notify(notification)",
|
|
ARG2, sizeof(struct vki_sigevent) );
|
|
}
|
|
|
|
PRE(sys_mq_getsetattr)
|
|
{
|
|
PRINT("sys_mq_getsetattr( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, 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 *)(Addr)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( %ld, %#" FMT_REGWORD "x )", SARG1, 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_settime64)
|
|
{
|
|
PRINT("sys_clock_settime64( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "clock_settime64",
|
|
vki_clockid_t, clk_id, const struct timespec64 *, tp);
|
|
pre_read_timespec64(tid, "clock_settime64(tp)", ARG2);
|
|
}
|
|
|
|
PRE(sys_clock_gettime)
|
|
{
|
|
PRINT("sys_clock_gettime( %ld, %#" FMT_REGWORD "x )" , SARG1, 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_gettime64)
|
|
{
|
|
PRINT("sys_clock_gettime64( %ld, %#" FMT_REGWORD "x )" , SARG1, ARG2);
|
|
PRE_REG_READ2(long, "clock_gettime64",
|
|
vki_clockid_t, clk_id, struct vki_timespec64 *, tp);
|
|
PRE_MEM_WRITE ( "clock_gettime64(tp)", ARG2,
|
|
sizeof(struct vki_timespec64) );
|
|
}
|
|
POST(sys_clock_gettime64)
|
|
{
|
|
POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec64) );
|
|
}
|
|
|
|
PRE(sys_clock_getres)
|
|
{
|
|
PRINT("sys_clock_getres( %ld, %#" FMT_REGWORD "x )" , SARG1, 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_getres_time64)
|
|
{
|
|
PRINT("sys_clock_getres_time64( %ld, %#" FMT_REGWORD "x )" , SARG1, ARG2);
|
|
// Nb: we can't use "RES" as the param name because that's a macro
|
|
// defined above!
|
|
PRE_REG_READ2(long, "clock_getres_time64",
|
|
vki_clockid_t, clk_id, struct vki_timespec64 *, res);
|
|
if (ARG2 != 0)
|
|
PRE_MEM_WRITE( "clock_getres_time64(res)", ARG2,
|
|
sizeof(struct vki_timespec64) );
|
|
}
|
|
POST(sys_clock_getres_time64)
|
|
{
|
|
if (ARG2 != 0)
|
|
POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec64) );
|
|
}
|
|
|
|
PRE(sys_clock_nanosleep)
|
|
{
|
|
*flags |= SfMayBlock|SfPostOnFail;
|
|
PRINT("sys_clock_nanosleep( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )",
|
|
SARG1, SARG2, 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 && ERR == VKI_EINTR)
|
|
POST_MEM_WRITE( ARG4, sizeof(struct vki_timespec) );
|
|
}
|
|
|
|
PRE(sys_clock_nanosleep_time64)
|
|
{
|
|
*flags |= SfMayBlock|SfPostOnFail;
|
|
PRINT("sys_clock_nanosleep_time64( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )",
|
|
SARG1, SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(int32_t, "clock_nanosleep_time64",
|
|
vki_clockid_t, clkid, int, flags,
|
|
const struct vki_timespec64 *, rqtp,
|
|
struct vki_timespec64 *, rmtp);
|
|
pre_read_timespec64(tid, "clock_nanosleep_time64(rqtp)", ARG3);
|
|
if (ARG4 != 0)
|
|
PRE_MEM_WRITE( "clock_nanosleep_time64(rmtp)", ARG4,
|
|
sizeof(struct vki_timespec64) );
|
|
}
|
|
POST(sys_clock_nanosleep_time64)
|
|
{
|
|
if (ARG4 != 0 && FAILURE && ERR == VKI_EINTR)
|
|
POST_MEM_WRITE( ARG4, sizeof(struct vki_timespec64) );
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
timer_* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_timer_create)
|
|
{
|
|
PRINT("sys_timer_create( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "timer_create",
|
|
vki_clockid_t, clockid, struct sigevent *, evp,
|
|
vki_timer_t *, timerid);
|
|
if (ARG2 != 0) {
|
|
struct vki_sigevent *evp = (struct vki_sigevent *) (Addr)ARG2;
|
|
PRE_MEM_READ( "timer_create(evp.sigev_value)", (Addr)&evp->sigev_value,
|
|
sizeof(vki_sigval_t) );
|
|
PRE_MEM_READ( "timer_create(evp.sigev_signo)", (Addr)&evp->sigev_signo,
|
|
sizeof(int) );
|
|
PRE_MEM_READ( "timer_create(evp.sigev_notify)", (Addr)&evp->sigev_notify,
|
|
sizeof(int) );
|
|
if (ML_(safe_to_deref)(&evp->sigev_notify, sizeof(int))
|
|
&& (evp->sigev_notify & VKI_SIGEV_THREAD_ID) != 0)
|
|
PRE_MEM_READ( "timer_create(evp.sigev_notify_thread_id)",
|
|
(Addr)&evp->vki_sigev_notify_thread_id, sizeof(int) );
|
|
}
|
|
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( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1,SARG2,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_settime64)
|
|
{
|
|
PRINT("sys_timer_settime64( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1,SARG2,ARG3,ARG4);
|
|
PRE_REG_READ4(long, "timer_settime64",
|
|
vki_timer_t, timerid, int, flags,
|
|
const struct vki_itimerspec64 *, value,
|
|
struct vki_itimerspec64 *, ovalue);
|
|
PRE_MEM_READ( "timer_settime64(value)", ARG3,
|
|
sizeof(struct vki_itimerspec64) );
|
|
if (ARG4 != 0)
|
|
PRE_MEM_WRITE( "timer_settime64(ovalue)", ARG4,
|
|
sizeof(struct vki_itimerspec64) );
|
|
}
|
|
POST(sys_timer_settime64)
|
|
{
|
|
if (ARG4 != 0)
|
|
POST_MEM_WRITE( ARG4, sizeof(struct vki_itimerspec64) );
|
|
}
|
|
|
|
PRE(sys_timer_gettime)
|
|
{
|
|
PRINT("sys_timer_gettime( %ld, %#" FMT_REGWORD "x )", SARG1, 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_gettime64)
|
|
{
|
|
PRINT("sys_timer_gettime64( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "timer_gettime64",
|
|
vki_timer_t, timerid, struct vki_itimerspec64 *, value);
|
|
PRE_MEM_WRITE( "timer_gettime64(value)", ARG2,
|
|
sizeof(struct vki_itimerspec64));
|
|
}
|
|
POST(sys_timer_gettime64)
|
|
{
|
|
POST_MEM_WRITE( ARG2, sizeof(struct vki_itimerspec64) );
|
|
}
|
|
|
|
PRE(sys_timer_getoverrun)
|
|
{
|
|
PRINT("sys_timer_getoverrun( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(long, "timer_getoverrun", vki_timer_t, timerid);
|
|
}
|
|
|
|
PRE(sys_timer_delete)
|
|
{
|
|
PRINT("sys_timer_delete( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
timerfd* wrappers
|
|
See also http://lwn.net/Articles/260172/ for an overview.
|
|
See also /usr/src/linux/fs/timerfd.c for the implementation.
|
|
------------------------------------------------------------------ */
|
|
|
|
/* Returns True if running on 2.6.22, else False (or False if
|
|
cannot be determined). */
|
|
static Bool linux_kernel_2_6_22(void)
|
|
{
|
|
static Int result = -1;
|
|
Int fd, read;
|
|
HChar release[64]; // large enough
|
|
SysRes res;
|
|
|
|
if (result == -1) {
|
|
res = VG_(open)("/proc/sys/kernel/osrelease", 0, 0);
|
|
if (sr_isError(res))
|
|
return False;
|
|
fd = sr_Res(res);
|
|
read = VG_(read)(fd, release, sizeof(release) - 1);
|
|
if (read < 0)
|
|
return False;
|
|
release[read] = 0;
|
|
VG_(close)(fd);
|
|
//VG_(printf)("kernel release = %s\n", release);
|
|
result = VG_(strncmp)(release, "2.6.22", 6) == 0
|
|
&& ! VG_(isdigit)(release[6]);
|
|
}
|
|
vg_assert(result == 0 || result == 1);
|
|
return result == 1;
|
|
}
|
|
|
|
PRE(sys_timerfd_create)
|
|
{
|
|
if (linux_kernel_2_6_22()) {
|
|
/* 2.6.22 kernel: timerfd system call. */
|
|
PRINT("sys_timerfd ( %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3);
|
|
PRE_REG_READ3(long, "sys_timerfd",
|
|
int, fd, int, clockid, const struct itimerspec *, tmr);
|
|
PRE_MEM_READ("timerfd(tmr)", ARG3,
|
|
sizeof(struct vki_itimerspec) );
|
|
if ((Word)ARG1 != -1L && !ML_(fd_allowed)(ARG1, "timerfd", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
/* 2.6.24 and later kernels: timerfd_create system call. */
|
|
PRINT("sys_timerfd_create (%ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(long, "timerfd_create", int, clockid, int, flags);
|
|
}
|
|
}
|
|
POST(sys_timerfd_create)
|
|
{
|
|
if (linux_kernel_2_6_22())
|
|
{
|
|
/* 2.6.22 kernel: timerfd system call. */
|
|
if (!ML_(fd_allowed)(RES, "timerfd", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless) (tid, RES);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 2.6.24 and later kernels: timerfd_create system call. */
|
|
if (!ML_(fd_allowed)(RES, "timerfd_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_timerfd_gettime)
|
|
{
|
|
PRINT("sys_timerfd_gettime ( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "timerfd_gettime",
|
|
int, ufd,
|
|
struct vki_itimerspec*, otmr);
|
|
if (!ML_(fd_allowed)(ARG1, "timerfd_gettime", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
else
|
|
PRE_MEM_WRITE("timerfd_gettime(result)",
|
|
ARG2, sizeof(struct vki_itimerspec));
|
|
}
|
|
POST(sys_timerfd_gettime)
|
|
{
|
|
if (RES == 0)
|
|
POST_MEM_WRITE(ARG2, sizeof(struct vki_itimerspec));
|
|
}
|
|
|
|
PRE(sys_timerfd_gettime64)
|
|
{
|
|
PRINT("sys_timerfd_gettime64 ( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "timerfd_gettime64",
|
|
int, ufd,
|
|
struct vki_itimerspec64*, otmr);
|
|
if (!ML_(fd_allowed)(ARG1, "timerfd_gettime64", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
else
|
|
PRE_MEM_WRITE("timerfd_gettime64(result)",
|
|
ARG2, sizeof(struct vki_itimerspec64));
|
|
}
|
|
POST(sys_timerfd_gettime64)
|
|
{
|
|
if (RES == 0)
|
|
POST_MEM_WRITE(ARG2, sizeof(struct vki_itimerspec64));
|
|
}
|
|
|
|
PRE(sys_timerfd_settime)
|
|
{
|
|
PRINT("sys_timerfd_settime ( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1, SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "timerfd_settime",
|
|
int, ufd,
|
|
int, flags,
|
|
const struct vki_itimerspec*, utmr,
|
|
struct vki_itimerspec*, otmr);
|
|
if (!ML_(fd_allowed)(ARG1, "timerfd_settime", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
else
|
|
{
|
|
PRE_MEM_READ("timerfd_settime(result)",
|
|
ARG3, sizeof(struct vki_itimerspec));
|
|
if (ARG4)
|
|
{
|
|
PRE_MEM_WRITE("timerfd_settime(result)",
|
|
ARG4, sizeof(struct vki_itimerspec));
|
|
}
|
|
}
|
|
}
|
|
POST(sys_timerfd_settime)
|
|
{
|
|
if (RES == 0 && ARG4 != 0)
|
|
POST_MEM_WRITE(ARG4, sizeof(struct vki_itimerspec));
|
|
}
|
|
|
|
PRE(sys_timerfd_settime64)
|
|
{
|
|
PRINT("sys_timerfd_settime64 ( %ld, %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1, SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "timerfd_settime64",
|
|
int, ufd,
|
|
int, flags,
|
|
const struct vki_itimerspec64*, utmr,
|
|
struct vki_itimerspec64*, otmr);
|
|
if (!ML_(fd_allowed)(ARG1, "timerfd_settime64", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
else
|
|
{
|
|
pre_read_itimerspec64 (tid, "timerfd_settime64(result)", ARG3);
|
|
if (ARG4)
|
|
{
|
|
PRE_MEM_WRITE("timerfd_settime64(result)",
|
|
ARG4, sizeof(struct vki_itimerspec64));
|
|
}
|
|
}
|
|
}
|
|
POST(sys_timerfd_settime64)
|
|
{
|
|
if (RES == 0 && ARG4 != 0)
|
|
POST_MEM_WRITE(ARG4, sizeof(struct vki_itimerspec64));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
capabilities wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_capget)
|
|
{
|
|
PRINT("sys_capget ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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) );
|
|
if (ARG2 != (Addr)NULL)
|
|
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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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 ( %" FMT_REGWORD "u )", 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 ( %" FMT_REGWORD "u )", 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%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "setreuid16", vki_old_uid_t, ruid, vki_old_uid_t, euid);
|
|
}
|
|
|
|
PRE(sys_setregid16)
|
|
{
|
|
PRINT("sys_setregid16 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "setregid16", vki_old_gid_t, rgid, vki_old_gid_t, egid);
|
|
}
|
|
|
|
PRE(sys_getgroups16)
|
|
{
|
|
PRINT("sys_getgroups16 ( %ld, %#" FMT_REGWORD "x )", SARG1, 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, %#" FMT_REGWORD "x )", (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 ( %#" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u, %ld )", ARG1, ARG2, ARG3,
|
|
ARG4, SARG5);
|
|
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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u, %ld )",
|
|
ARG1, ARG2, ARG3, ARG4, SARG5);
|
|
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 ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u, %ld )",
|
|
SARG1, ARG2, ARG3, ARG4, SARG5);
|
|
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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %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 ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG1, ARG2, ARG3, 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %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 ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
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 ( %ld, %#" FMT_REGWORD "x )", SARG1, 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 ( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2 );
|
|
PRE_REG_READ2(long, "sched_setparam",
|
|
vki_pid_t, pid, struct sched_param *, p);
|
|
PRE_MEM_READ( "sched_setparam(p)", ARG2, sizeof(struct vki_sched_param) );
|
|
}
|
|
POST(sys_sched_setparam)
|
|
{
|
|
POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) );
|
|
}
|
|
|
|
PRE(sys_sched_getparam)
|
|
{
|
|
PRINT("sched_getparam ( %ld, %#" FMT_REGWORD "x )", SARG1, 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_setattr)
|
|
{
|
|
struct vki_sched_attr *attr;
|
|
PRINT("sched_setattr ( %ld, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3 );
|
|
PRE_REG_READ3(long, "sched_setattr",
|
|
vki_pid_t, pid, struct sched_attr *, p, unsigned int, flags);
|
|
/* We need to be able to read at least the size field. */
|
|
PRE_MEM_READ( "sched_setattr(attr->size)", ARG2, sizeof(vki_uint32_t) );
|
|
attr = (struct vki_sched_attr *)(Addr)ARG2;
|
|
if (ML_(safe_to_deref)(attr,sizeof(vki_uint32_t)))
|
|
PRE_MEM_READ( "sched_setattr(attr)", (Addr)attr, attr->size);
|
|
}
|
|
|
|
PRE(sys_sched_getattr)
|
|
{
|
|
struct vki_sched_attr *attr;
|
|
PRINT("sched_getattr ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3, ARG4 );
|
|
PRE_REG_READ4(long, "sched_getattr",
|
|
vki_pid_t, pid, struct sched_attr *, p,
|
|
unsigned int, size, unsigned int, flags);
|
|
/* We need to be able to read at least the size field. */
|
|
PRE_MEM_READ( "sched_setattr(attr->size)", ARG2, sizeof(vki_uint32_t) );
|
|
/* And the kernel needs to be able to write to the whole struct size. */
|
|
attr = (struct vki_sched_attr *)(Addr)ARG2;
|
|
if (ML_(safe_to_deref)(attr,sizeof(vki_uint32_t)))
|
|
PRE_MEM_WRITE( "sched_setattr(attr)", (Addr)attr, attr->size);
|
|
}
|
|
POST(sys_sched_getattr)
|
|
{
|
|
struct vki_sched_attr *attr = (struct vki_sched_attr *)(Addr)ARG2;
|
|
POST_MEM_WRITE( (Addr)attr, attr->size );
|
|
}
|
|
|
|
PRE(sys_sched_getscheduler)
|
|
{
|
|
PRINT("sys_sched_getscheduler ( %ld )", SARG1);
|
|
PRE_REG_READ1(long, "sched_getscheduler", vki_pid_t, pid);
|
|
}
|
|
|
|
PRE(sys_sched_setscheduler)
|
|
{
|
|
PRINT("sys_sched_setscheduler ( %ld, %ld, %#" FMT_REGWORD "x )",
|
|
SARG1, SARG2, 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 ( %ld )", SARG1);
|
|
PRE_REG_READ1(long, "sched_get_priority_max", int, policy);
|
|
}
|
|
|
|
PRE(sys_sched_get_priority_min)
|
|
{
|
|
PRINT("sched_get_priority_min ( %ld )", SARG1);
|
|
PRE_REG_READ1(long, "sched_get_priority_min", int, policy);
|
|
}
|
|
|
|
PRE(sys_sched_rr_get_interval)
|
|
{
|
|
PRINT("sys_sched_rr_get_interval ( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2);
|
|
PRE_REG_READ2(int, "sched_rr_get_interval",
|
|
vki_pid_t, pid,
|
|
struct vki_timespec *, tp);
|
|
PRE_MEM_WRITE("sched_rr_get_interval(timespec)",
|
|
ARG2, sizeof(struct vki_timespec));
|
|
}
|
|
|
|
POST(sys_sched_rr_get_interval)
|
|
{
|
|
POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec));
|
|
}
|
|
|
|
PRE(sys_sched_rr_get_interval_time64)
|
|
{
|
|
PRINT("sys_sched_rr_get_interval_time64 ( %ld, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2);
|
|
PRE_REG_READ2(int, "sched_rr_get_interval_time64",
|
|
vki_pid_t, pid,
|
|
struct vki_timespec *, tp);
|
|
PRE_MEM_WRITE("sched_rr_get_interval_time64(timespec)",
|
|
ARG2, sizeof(struct vki_timespec64));
|
|
}
|
|
|
|
POST(sys_sched_rr_get_interval_time64)
|
|
{
|
|
POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec64));
|
|
}
|
|
|
|
PRE(sys_sched_setaffinity)
|
|
{
|
|
PRINT("sched_setaffinity ( %ld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "sched_setaffinity",
|
|
vki_pid_t, pid, unsigned int, len, unsigned long *, mask);
|
|
PRE_MEM_READ( "sched_setaffinity(mask)", ARG3, ARG2);
|
|
}
|
|
|
|
PRE(sys_sched_getaffinity)
|
|
{
|
|
PRINT("sched_getaffinity ( %ld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1, 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);
|
|
}
|
|
|
|
PRE(sys_unshare)
|
|
{
|
|
PRINT("sys_unshare ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(int, "unshare", unsigned long, flags);
|
|
}
|
|
|
|
PRE(sys_setns)
|
|
{
|
|
PRINT("sys_setns ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(int, "setns",
|
|
int, fd,
|
|
int, nstype);
|
|
if (!ML_(fd_allowed)(ARG1, "setns", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
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 ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(int, "pipe", int *, filedes);
|
|
PRE_MEM_WRITE( "pipe(filedes)", ARG1, 2*sizeof(int) );
|
|
}
|
|
POST(sys_pipe)
|
|
{
|
|
Int *p = (Int *)(Addr)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]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* pipe2 (a kernel 2.6.twentysomething invention) is like pipe, except
|
|
there's a second arg containing flags to be applied to the new file
|
|
descriptors. It hardly seems worth the effort to factor out the
|
|
duplicated code, hence: */
|
|
PRE(sys_pipe2)
|
|
{
|
|
PRINT("sys_pipe2 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2);
|
|
PRE_REG_READ2(int, "pipe", int *, filedes, long, flags);
|
|
PRE_MEM_WRITE( "pipe2(filedes)", ARG1, 2*sizeof(int) );
|
|
}
|
|
POST(sys_pipe2)
|
|
{
|
|
Int *p = (Int *)(Addr)ARG1;
|
|
if (!ML_(fd_allowed)(p[0], "pipe2", tid, True) ||
|
|
!ML_(fd_allowed)(p[1], "pipe2", 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_dup3)
|
|
{
|
|
PRINT("sys_dup3 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "dup3", unsigned int, oldfd, unsigned int, newfd, int, flags);
|
|
if (!ML_(fd_allowed)(ARG2, "dup3", tid, True))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
POST(sys_dup3)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_named)(tid, RES);
|
|
}
|
|
|
|
PRE(sys_quotactl)
|
|
{
|
|
PRINT("sys_quotactl (0x%" FMT_REGWORD "x, %#" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x, 0x%" FMT_REGWORD "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( %ld, %ld, %#" FMT_REGWORD "x, %ld, %#" FMT_REGWORD "x )",
|
|
SARG1, SARG2, ARG3, SARG4, 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) );
|
|
}
|
|
|
|
PRE(sys_sync_file_range)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
#if VG_WORDSIZE == 4
|
|
PRINT("sys_sync_file_range ( %ld, %lld, %lld, %#" FMT_REGWORD "x )",
|
|
SARG1, (Long)MERGE64(ARG2,ARG3), (Long)MERGE64(ARG4,ARG5),ARG6);
|
|
PRE_REG_READ6(long, "sync_file_range",
|
|
int, fd,
|
|
unsigned, MERGE64_FIRST(offset), unsigned, MERGE64_SECOND(offset),
|
|
unsigned, MERGE64_FIRST(nbytes), unsigned, MERGE64_SECOND(nbytes),
|
|
unsigned int, flags);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_sync_file_range ( %ld, %ld, %ld, %#lx )",
|
|
SARG1, SARG2, SARG3, ARG4);
|
|
PRE_REG_READ4(long, "sync_file_range",
|
|
int, fd, vki_loff_t, offset, vki_loff_t, nbytes,
|
|
unsigned int, flags);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
if (!ML_(fd_allowed)(ARG1, "sync_file_range", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
PRE(sys_sync_file_range2)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
#if VG_WORDSIZE == 4
|
|
PRINT("sys_sync_file_range2 ( %ld, %" FMT_REGWORD "u, %lld, %lld )",
|
|
SARG1, ARG2, (Long)MERGE64(ARG3,ARG4), (Long)MERGE64(ARG5,ARG6));
|
|
PRE_REG_READ6(long, "sync_file_range2",
|
|
int, fd, unsigned int, flags,
|
|
unsigned, MERGE64_FIRST(offset), unsigned, MERGE64_SECOND(offset),
|
|
unsigned, MERGE64_FIRST(nbytes), unsigned, MERGE64_SECOND(nbytes));
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_sync_file_range2 ( %ld, %lu, %ld, %ld )",
|
|
SARG1, ARG2, SARG3, SARG4);
|
|
PRE_REG_READ4(long, "sync_file_range2",
|
|
int, fd, unsigned int, flags,
|
|
vki_loff_t, offset, vki_loff_t, nbytes);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
if (!ML_(fd_allowed)(ARG1, "sync_file_range2", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
PRE(sys_stime)
|
|
{
|
|
PRINT("sys_stime ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(int, "stime", vki_time_t*, t);
|
|
PRE_MEM_READ( "stime(t)", ARG1, sizeof(vki_time_t) );
|
|
}
|
|
|
|
PRE(sys_perf_event_open)
|
|
{
|
|
struct vki_perf_event_attr *attr;
|
|
PRINT("sys_perf_event_open ( %#" FMT_REGWORD "x, %ld, %ld, %ld, %#"
|
|
FMT_REGWORD "x )", ARG1, SARG2, SARG3, SARG4, ARG5);
|
|
PRE_REG_READ5(long, "perf_event_open",
|
|
struct vki_perf_event_attr *, attr,
|
|
vki_pid_t, pid, int, cpu, int, group_fd,
|
|
unsigned long, flags);
|
|
attr = (struct vki_perf_event_attr *)(Addr)ARG1;
|
|
PRE_MEM_READ( "perf_event_open(attr->size)",
|
|
(Addr)&attr->size, sizeof(attr->size) );
|
|
PRE_MEM_READ( "perf_event_open(attr)",
|
|
(Addr)attr, attr->size );
|
|
}
|
|
|
|
POST(sys_perf_event_open)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "perf_event_open", 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_getcpu)
|
|
{
|
|
PRINT("sys_getcpu ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x )" , ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(int, "getcpu",
|
|
unsigned *, cpu, unsigned *, node, struct vki_getcpu_cache *, tcache);
|
|
if (ARG1 != 0)
|
|
PRE_MEM_WRITE( "getcpu(cpu)", ARG1, sizeof(unsigned) );
|
|
if (ARG2 != 0)
|
|
PRE_MEM_WRITE( "getcpu(node)", ARG2, sizeof(unsigned) );
|
|
if (ARG3 != 0)
|
|
PRE_MEM_WRITE( "getcpu(tcache)", ARG3, sizeof(struct vki_getcpu_cache) );
|
|
}
|
|
|
|
POST(sys_getcpu)
|
|
{
|
|
if (ARG1 != 0)
|
|
POST_MEM_WRITE( ARG1, sizeof(unsigned) );
|
|
if (ARG2 != 0)
|
|
POST_MEM_WRITE( ARG2, sizeof(unsigned) );
|
|
if (ARG3 != 0)
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_getcpu_cache) );
|
|
}
|
|
|
|
PRE(sys_move_pages)
|
|
{
|
|
PRINT("sys_move_pages ( %ld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(int, "move_pages",
|
|
vki_pid_t, pid, unsigned long, nr_pages, const void **, pages,
|
|
const int *, nodes, int *, status, int, flags);
|
|
PRE_MEM_READ("move_pages(pages)", ARG3, ARG2 * sizeof(void *));
|
|
if (ARG4)
|
|
PRE_MEM_READ("move_pages(nodes)", ARG4, ARG2 * sizeof(int));
|
|
PRE_MEM_WRITE("move_pages(status)", ARG5, ARG2 * sizeof(int));
|
|
}
|
|
|
|
POST(sys_move_pages)
|
|
{
|
|
POST_MEM_WRITE(ARG5, ARG2 * sizeof(int));
|
|
}
|
|
|
|
PRE(sys_getrandom)
|
|
{
|
|
PRINT("sys_getrandom ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )" , ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(int, "getrandom",
|
|
char *, buf, vki_size_t, count, unsigned int, flags);
|
|
PRE_MEM_WRITE( "getrandom(cpu)", ARG1, ARG2 );
|
|
}
|
|
|
|
POST(sys_getrandom)
|
|
{
|
|
POST_MEM_WRITE( ARG1, ARG2 );
|
|
}
|
|
|
|
PRE(sys_memfd_create)
|
|
{
|
|
PRINT("sys_memfd_create ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )" ,
|
|
ARG1, ARG2);
|
|
PRE_REG_READ2(int, "memfd_create",
|
|
char *, uname, unsigned int, flags);
|
|
PRE_MEM_RASCIIZ( "memfd_create(uname)", ARG1 );
|
|
}
|
|
|
|
POST(sys_memfd_create)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "memfd_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_memfd_secret)
|
|
{
|
|
PRINT("sys_memfd_secret ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(int, "memfd_secret", unsigned int, flags);
|
|
}
|
|
|
|
POST(sys_memfd_secret)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "memfd_secret", 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_membarrier)
|
|
{
|
|
PRINT("sys_membarrier ( %#" FMT_REGWORD "x )", ARG1);
|
|
PRE_REG_READ1(int, "membarrier", int, flags);
|
|
}
|
|
|
|
PRE(sys_syncfs)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_syncfs ( %" FMT_REGWORD "u )", ARG1);
|
|
PRE_REG_READ1(long, "syncfs", unsigned int, fd);
|
|
}
|
|
|
|
PRE(sys_statx)
|
|
{
|
|
FUSE_COMPATIBLE_MAY_BLOCK();
|
|
PRINT("sys_statx ( %ld, %#" FMT_REGWORD "x(%s), %ld, %ld, %#" FMT_REGWORD "x )",
|
|
(Word)ARG1,ARG2,(char*)(Addr)ARG2,(Word)ARG3,(Word)ARG4,ARG5);
|
|
PRE_REG_READ5(long, "statx",
|
|
int, dirfd, char *, filename, int, flags,
|
|
unsigned int, mask, struct statx *, buf);
|
|
// Work around Rust's dubious use of statx, as described here:
|
|
// https://github.com/rust-lang/rust/blob/
|
|
// ccd238309f9dce92a05a23c2959e2819668c69a4/
|
|
// src/libstd/sys/unix/fs.rs#L128-L142
|
|
// in which it passes NULL for both filename and buf, and then looks at the
|
|
// return value, so as to determine whether or not this syscall is supported.
|
|
Bool both_filename_and_buf_are_null = ARG2 == 0 && ARG5 == 0;
|
|
if (!both_filename_and_buf_are_null) {
|
|
PRE_MEM_RASCIIZ( "statx(filename)", ARG2 );
|
|
PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
|
|
}
|
|
}
|
|
POST(sys_statx)
|
|
{
|
|
POST_MEM_WRITE( ARG5, sizeof(struct vki_statx) );
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
utime wrapper
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_utime)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_utime ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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 ( %" FMT_REGWORD "u, %ld, %" FMT_REGWORD "u )",
|
|
ARG1, SARG2, ARG3);
|
|
PRE_REG_READ3(vki_off_t, "lseek",
|
|
unsigned int, fd, vki_off_t, offset, unsigned int, whence);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
readahead wrapper
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_readahead)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
#if VG_WORDSIZE == 4
|
|
PRINT("sys_readahead ( %ld, %lld, %" FMT_REGWORD "u )",
|
|
SARG1, (Long)MERGE64(ARG2,ARG3), ARG4);
|
|
PRE_REG_READ4(vki_off_t, "readahead",
|
|
int, fd, unsigned, MERGE64_FIRST(offset),
|
|
unsigned, MERGE64_SECOND(offset), vki_size_t, count);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_readahead ( %ld, %ld, %lu )", SARG1, SARG2, ARG3);
|
|
PRE_REG_READ3(vki_off_t, "readahead",
|
|
int, fd, vki_loff_t, offset, vki_size_t, count);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
if (!ML_(fd_allowed)(ARG1, "readahead", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
sig* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_sigpending)
|
|
{
|
|
PRINT( "sys_sigpending ( %#" FMT_REGWORD "x )", 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) \
|
|
|| defined(VGP_arm_linux) || defined(VGP_mips32_linux) \
|
|
|| defined(VGP_nanomips_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 ( %ld, %#lx, %#lx )", SARG1, 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*)(Addr)ARG2;
|
|
oldset = (vki_old_sigset_t*)(Addr)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));
|
|
}
|
|
|
|
/* Convert from non-RT to RT sigset_t's */
|
|
static
|
|
void convert_sigset_to_rt(const vki_old_sigset_t *oldset, vki_sigset_t *set)
|
|
{
|
|
VG_(sigemptyset)(set);
|
|
set->sig[0] = *oldset;
|
|
}
|
|
PRE(sys_sigaction)
|
|
{
|
|
vki_sigaction_toK_t new, *newp;
|
|
vki_sigaction_fromK_t old, *oldp;
|
|
|
|
PRINT("sys_sigaction ( %ld, %#lx, %#lx )", SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(int, "sigaction",
|
|
int, signum, const struct old_sigaction *, act,
|
|
struct old_sigaction *, oldact);
|
|
|
|
newp = oldp = NULL;
|
|
|
|
if (ARG2 != 0) {
|
|
struct vki_old_sigaction *sa = (struct vki_old_sigaction *)(Addr)ARG2;
|
|
PRE_MEM_READ( "sigaction(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
|
|
PRE_MEM_READ( "sigaction(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
|
|
PRE_MEM_READ( "sigaction(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
|
|
if (ML_(safe_to_deref)(sa,sizeof(struct vki_old_sigaction))
|
|
&& (sa->sa_flags & VKI_SA_RESTORER))
|
|
PRE_MEM_READ( "sigaction(act->sa_restorer)", (Addr)&sa->sa_restorer, sizeof(sa->sa_restorer));
|
|
}
|
|
|
|
if (ARG3 != 0) {
|
|
PRE_MEM_WRITE( "sigaction(oldact)", ARG3, sizeof(struct vki_old_sigaction));
|
|
oldp = &old;
|
|
}
|
|
|
|
/* If the new or old sigaction is not NULL, but the structs
|
|
aren't accessible then sigaction returns EFAULT and we cannot
|
|
use either struct for our own bookkeeping. Just fail early. */
|
|
if (ARG2 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG2,
|
|
sizeof(struct vki_old_sigaction))) {
|
|
VG_(umsg)("Warning: bad act handler address %p in sigaction()\n",
|
|
(void *)(Addr)ARG2);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
} else if ((ARG3 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG3,
|
|
sizeof(struct vki_old_sigaction)))) {
|
|
VG_(umsg)("Warning: bad oldact handler address %p in sigaction()\n",
|
|
(void *)(Addr)ARG3);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
} else {
|
|
if (ARG2 != 0) {
|
|
struct vki_old_sigaction *oldnew =
|
|
(struct vki_old_sigaction *)(Addr)ARG2;
|
|
|
|
new.ksa_handler = oldnew->ksa_handler;
|
|
new.sa_flags = oldnew->sa_flags;
|
|
new.sa_restorer = oldnew->sa_restorer;
|
|
convert_sigset_to_rt(&oldnew->sa_mask, &new.sa_mask);
|
|
newp = &new;
|
|
}
|
|
|
|
SET_STATUS_from_SysRes( VG_(do_sys_sigaction)(ARG1, newp, oldp) );
|
|
|
|
if (ARG3 != 0 && SUCCESS && RES == 0) {
|
|
struct vki_old_sigaction *oldold =
|
|
(struct vki_old_sigaction *)(Addr)ARG3;
|
|
|
|
oldold->ksa_handler = oldp->ksa_handler;
|
|
oldold->sa_flags = oldp->sa_flags;
|
|
oldold->sa_restorer = oldp->sa_restorer;
|
|
oldold->sa_mask = oldp->sa_mask.sig[0];
|
|
}
|
|
}
|
|
}
|
|
POST(sys_sigaction)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES == 0 && ARG3 != 0)
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_old_sigaction));
|
|
}
|
|
#endif
|
|
|
|
PRE(sys_signalfd)
|
|
{
|
|
PRINT("sys_signalfd ( %d, %#" FMT_REGWORD "x, %llu )", (Int)ARG1, ARG2,
|
|
(ULong)ARG3);
|
|
PRE_REG_READ3(long, "sys_signalfd",
|
|
int, fd, vki_sigset_t *, sigmask, vki_size_t, sigsetsize);
|
|
PRE_MEM_READ( "signalfd(sigmask)", ARG2, sizeof(vki_sigset_t) );
|
|
if ((int)ARG1 != -1 && !ML_(fd_allowed)(ARG1, "signalfd", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
POST(sys_signalfd)
|
|
{
|
|
if (!ML_(fd_allowed)(RES, "signalfd", 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_signalfd4)
|
|
{
|
|
PRINT("sys_signalfd4 ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %ld )",
|
|
SARG1, ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(long, "sys_signalfd4",
|
|
int, fd, vki_sigset_t *, sigmask, vki_size_t, sigsetsize, int, flags);
|
|
PRE_MEM_READ( "signalfd(sigmask)", ARG2, sizeof(vki_sigset_t) );
|
|
if ((int)ARG1 != -1 && !ML_(fd_allowed)(ARG1, "signalfd", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
POST(sys_signalfd4)
|
|
{
|
|
if (!ML_(fd_allowed)(RES, "signalfd4", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless) (tid, RES);
|
|
}
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
rt_sig* wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_rt_sigaction)
|
|
{
|
|
PRINT("sys_rt_sigaction ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG1, 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) {
|
|
vki_sigaction_toK_t *sa = (vki_sigaction_toK_t *)(Addr)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 (ML_(safe_to_deref)(sa,sizeof(vki_sigaction_toK_t))
|
|
&& (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(vki_sigaction_fromK_t));
|
|
|
|
/* If the new or old sigaction is not NULL, but the structs
|
|
aren't accessible then sigaction returns EFAULT and we cannot
|
|
use either struct for our own bookkeeping. Just fail early. */
|
|
if (ARG2 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG2,
|
|
sizeof(vki_sigaction_toK_t))) {
|
|
VG_(umsg)("Warning: bad act handler address %p in rt_sigaction()\n",
|
|
(void *)(Addr)ARG2);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
} else if ((ARG3 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG3,
|
|
sizeof(vki_sigaction_fromK_t)))) {
|
|
VG_(umsg)("Warning: bad oldact handler address %p in rt_sigaction()\n",
|
|
(void *)(Addr)ARG3);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
} else {
|
|
|
|
// 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 vki_sigaction_toK_t *)(Addr)ARG2,
|
|
(vki_sigaction_fromK_t *)(Addr)ARG3)
|
|
);
|
|
}
|
|
}
|
|
POST(sys_rt_sigaction)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES == 0 && ARG3 != 0)
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_sigaction_fromK_t));
|
|
}
|
|
|
|
PRE(sys_rt_sigprocmask)
|
|
{
|
|
PRINT("sys_rt_sigprocmask ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG1, ARG2, ARG3, 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.
|
|
// Since we want to use the set and oldset for bookkeeping we also want
|
|
// to make sure they are addressable otherwise, like the kernel, we EFAULT.
|
|
if (sizeof(vki_sigset_t) != ARG4)
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
else if (ARG2 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG2, sizeof(vki_sigset_t))) {
|
|
VG_(dmsg)("Warning: Bad set handler address %p in sigprocmask\n",
|
|
(void *)(Addr)ARG2);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
}
|
|
else if (ARG3 != 0
|
|
&& ! ML_(safe_to_deref)((void *)(Addr)ARG3, sizeof(vki_sigset_t))) {
|
|
VG_(dmsg)("Warning: Bad oldset address %p in sigprocmask\n",
|
|
(void *)(Addr)ARG3);
|
|
SET_STATUS_Failure ( VKI_EFAULT );
|
|
}
|
|
|
|
else {
|
|
SET_STATUS_from_SysRes(
|
|
VG_(do_sys_sigprocmask) ( tid, ARG1 /*how*/,
|
|
(vki_sigset_t*) (Addr)ARG2,
|
|
(vki_sigset_t*) (Addr)ARG3 )
|
|
);
|
|
}
|
|
|
|
if (SUCCESS)
|
|
*flags |= SfPollAfter;
|
|
}
|
|
POST(sys_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 ( %#" FMT_REGWORD "x )", 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 ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2, ARG3, 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_sigtimedwait_time64)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_rt_sigtimedwait_time64 ( %#" FMT_REGWORD "x, %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "rt_sigtimedwait_time64",
|
|
const vki_sigset_t *, set, vki_siginfo_t *, info,
|
|
const struct vki_timespec64 *, timeout,
|
|
vki_size_t, sigsetsize);
|
|
if (ARG1 != 0)
|
|
PRE_MEM_READ( "rt_sigtimedwait_time64(set)", ARG1, sizeof(vki_sigset_t) );
|
|
if (ARG2 != 0)
|
|
PRE_MEM_WRITE( "rt_sigtimedwait_time64(info)", ARG2,
|
|
sizeof(vki_siginfo_t) );
|
|
if (ARG3 != 0)
|
|
pre_read_timespec64(tid, "rt_sigtimedwait_time64(timeout)", ARG3);
|
|
}
|
|
POST(sys_rt_sigtimedwait_time64)
|
|
{
|
|
if (ARG2 != 0)
|
|
POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) );
|
|
}
|
|
|
|
PRE(sys_rt_sigqueueinfo)
|
|
{
|
|
PRINT("sys_rt_sigqueueinfo(%ld, %ld, %#" FMT_REGWORD "x)",
|
|
SARG1, SARG2, 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, VKI_SI_MAX_SIZE );
|
|
}
|
|
POST(sys_rt_sigqueueinfo)
|
|
{
|
|
if (!ML_(client_signal_OK)(ARG2))
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
|
|
PRE(sys_rt_tgsigqueueinfo)
|
|
{
|
|
PRINT("sys_rt_tgsigqueueinfo(%ld, %ld, %ld, %#" FMT_REGWORD "x)",
|
|
SARG1, SARG2, SARG3, ARG4);
|
|
PRE_REG_READ4(long, "rt_tgsigqueueinfo",
|
|
int, tgid, int, pid, int, sig, vki_siginfo_t *, uinfo);
|
|
if (ARG3 != 0)
|
|
PRE_MEM_READ( "rt_tgsigqueueinfo(uinfo)", ARG4, VKI_SI_MAX_SIZE );
|
|
}
|
|
|
|
POST(sys_rt_tgsigqueueinfo)
|
|
{
|
|
if (!ML_(client_signal_OK)(ARG3))
|
|
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 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
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) );
|
|
if (ML_(safe_to_deref)((vki_sigset_t *) (Addr)ARG1, sizeof(vki_sigset_t))) {
|
|
VG_(sigdelset)((vki_sigset_t *) (Addr)ARG1, VG_SIGVGKILL);
|
|
/* We cannot mask VG_SIGVGKILL, as otherwise this thread would not
|
|
be killable by VG_(nuke_all_threads_except).
|
|
We thus silently ignore the user request to mask this signal.
|
|
Note that this is similar to what is done for e.g.
|
|
sigprocmask (see m_signals.c calculate_SKSS_from_SCSS). */
|
|
} else {
|
|
SET_STATUS_Failure(VKI_EFAULT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Generic handler for sys_ipc
|
|
Depending on the platform, some syscalls (e.g. semctl, semop, ...)
|
|
are either direct system calls, or are all implemented via sys_ipc.
|
|
------------------------------------------------------------------ */
|
|
#ifdef __NR_ipc
|
|
static Addr deref_Addr ( ThreadId tid, Addr a, const HChar* s )
|
|
{
|
|
Addr* a_p = (Addr*)a;
|
|
PRE_MEM_READ( s, (Addr)a_p, sizeof(Addr) );
|
|
return *a_p;
|
|
}
|
|
|
|
static Bool semctl_cmd_has_4args (UWord cmd)
|
|
{
|
|
switch (cmd & ~VKI_IPC_64)
|
|
{
|
|
case VKI_IPC_INFO:
|
|
case VKI_SEM_INFO:
|
|
case VKI_IPC_STAT:
|
|
case VKI_SEM_STAT:
|
|
case VKI_IPC_SET:
|
|
case VKI_GETALL:
|
|
case VKI_SETALL:
|
|
return True;
|
|
default:
|
|
return False;
|
|
}
|
|
}
|
|
|
|
PRE(sys_ipc)
|
|
{
|
|
PRINT("sys_ipc ( %lu, %ld, %ld, %ld, %#lx, %ld )",
|
|
ARG1, SARG2, SARG3, SARG4, ARG5, SARG6);
|
|
|
|
switch (ARG1 /* call */) {
|
|
case VKI_SEMOP:
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
ML_(generic_PRE_sys_semop)( tid, ARG2, ARG5, ARG3 );
|
|
*flags |= SfMayBlock;
|
|
break;
|
|
case VKI_SEMGET:
|
|
PRE_REG_READ4(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third);
|
|
break;
|
|
case VKI_SEMCTL:
|
|
{
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
UWord arg;
|
|
if (semctl_cmd_has_4args(ARG4))
|
|
arg = deref_Addr( tid, ARG5, "semctl(arg)" );
|
|
else
|
|
arg = 0;
|
|
ML_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg );
|
|
break;
|
|
}
|
|
case VKI_SEMTIMEDOP:
|
|
#ifdef VGP_s390x_linux
|
|
/* On s390x Linux platforms the sys_ipc semtimedop call has four instead
|
|
of five parameters, where the timeout is passed in the third instead of
|
|
the fifth. */
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, long, third,
|
|
void *, ptr);
|
|
ML_(generic_PRE_sys_semtimedop)( tid, ARG2, ARG5, ARG3, ARG4 );
|
|
#else
|
|
PRE_REG_READ6(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr, long, fifth);
|
|
ML_(generic_PRE_sys_semtimedop)( tid, ARG2, ARG5, ARG3, ARG6 );
|
|
#endif
|
|
*flags |= SfMayBlock;
|
|
break;
|
|
case VKI_MSGSND:
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
ML_(linux_PRE_sys_msgsnd)( tid, ARG2, ARG5, ARG3, ARG4 );
|
|
if ((ARG4 & VKI_IPC_NOWAIT) == 0)
|
|
*flags |= SfMayBlock;
|
|
break;
|
|
case VKI_MSGRCV:
|
|
{
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
Addr msgp;
|
|
Word msgtyp;
|
|
|
|
msgp = deref_Addr( tid, (Addr) (&((struct vki_ipc_kludge *)(Addr)ARG5)->msgp),
|
|
"msgrcv(msgp)" );
|
|
msgtyp = deref_Addr( tid,
|
|
(Addr) (&((struct vki_ipc_kludge *)(Addr)ARG5)->msgtyp),
|
|
"msgrcv(msgp)" );
|
|
|
|
ML_(linux_PRE_sys_msgrcv)( tid, ARG2, msgp, ARG3, msgtyp, ARG4 );
|
|
|
|
if ((ARG4 & VKI_IPC_NOWAIT) == 0)
|
|
*flags |= SfMayBlock;
|
|
break;
|
|
}
|
|
case VKI_MSGGET:
|
|
PRE_REG_READ3(int, "ipc", vki_uint, call, int, first, int, second);
|
|
break;
|
|
case VKI_MSGCTL:
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
ML_(linux_PRE_sys_msgctl)( tid, ARG2, ARG3, ARG5 );
|
|
break;
|
|
case VKI_SHMAT:
|
|
{
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
UWord w;
|
|
PRE_MEM_WRITE( "shmat(raddr)", ARG4, sizeof(Addr) );
|
|
w = ML_(generic_PRE_sys_shmat)( tid, ARG2, ARG5, ARG3 );
|
|
if (w == 0)
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
else
|
|
ARG5 = w;
|
|
break;
|
|
}
|
|
case VKI_SHMDT:
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
if (!ML_(generic_PRE_sys_shmdt)(tid, ARG5))
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
break;
|
|
case VKI_SHMGET:
|
|
PRE_REG_READ4(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third);
|
|
if (ARG4 & VKI_SHM_HUGETLB) {
|
|
static Bool warning_given = False;
|
|
ARG4 &= ~VKI_SHM_HUGETLB;
|
|
if (!warning_given) {
|
|
warning_given = True;
|
|
VG_(umsg)(
|
|
"WARNING: valgrind ignores shmget(shmflg) SHM_HUGETLB\n");
|
|
}
|
|
}
|
|
break;
|
|
case VKI_SHMCTL: /* IPCOP_shmctl */
|
|
PRE_REG_READ5(int, "ipc",
|
|
vki_uint, call, int, first, int, second, int, third,
|
|
void *, ptr);
|
|
ML_(generic_PRE_sys_shmctl)( tid, ARG2, ARG3, ARG5 );
|
|
break;
|
|
default:
|
|
VG_(message)(Vg_DebugMsg, "FATAL: unhandled syscall(ipc) %lu\n", ARG1 );
|
|
VG_(core_panic)("... bye!\n");
|
|
break; /*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
POST(sys_ipc)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
switch (ARG1 /* call */) {
|
|
case VKI_SEMOP:
|
|
case VKI_SEMGET:
|
|
break;
|
|
case VKI_SEMCTL:
|
|
{
|
|
UWord arg;
|
|
if (semctl_cmd_has_4args(ARG4))
|
|
arg = deref_Addr( tid, ARG5, "semctl(arg)" );
|
|
else
|
|
arg = 0;
|
|
ML_(generic_POST_sys_semctl)( tid, RES, ARG2, ARG3, ARG4, arg );
|
|
break;
|
|
}
|
|
case VKI_SEMTIMEDOP:
|
|
case VKI_MSGSND:
|
|
break;
|
|
case VKI_MSGRCV:
|
|
{
|
|
Addr msgp;
|
|
Word msgtyp;
|
|
|
|
msgp = deref_Addr( tid,
|
|
(Addr) (&((struct vki_ipc_kludge *)(Addr)ARG5)->msgp),
|
|
"msgrcv(msgp)" );
|
|
msgtyp = deref_Addr( tid,
|
|
(Addr) (&((struct vki_ipc_kludge *)(Addr)ARG5)->msgtyp),
|
|
"msgrcv(msgp)" );
|
|
|
|
ML_(linux_POST_sys_msgrcv)( tid, RES, ARG2, msgp, ARG3, msgtyp, ARG4 );
|
|
break;
|
|
}
|
|
case VKI_MSGGET:
|
|
break;
|
|
case VKI_MSGCTL:
|
|
ML_(linux_POST_sys_msgctl)( tid, RES, ARG2, ARG3, ARG5 );
|
|
break;
|
|
case VKI_SHMAT:
|
|
{
|
|
Addr addr;
|
|
|
|
/* force readability. before the syscall it is
|
|
* indeed uninitialized, as can be seen in
|
|
* glibc/sysdeps/unix/sysv/linux/shmat.c */
|
|
POST_MEM_WRITE( ARG4, sizeof( Addr ) );
|
|
|
|
addr = deref_Addr ( tid, ARG4, "shmat(addr)" );
|
|
ML_(generic_POST_sys_shmat)( tid, addr, ARG2, ARG5, ARG3 );
|
|
break;
|
|
}
|
|
case VKI_SHMDT:
|
|
ML_(generic_POST_sys_shmdt)( tid, RES, ARG5 );
|
|
break;
|
|
case VKI_SHMGET:
|
|
break;
|
|
case VKI_SHMCTL:
|
|
ML_(generic_POST_sys_shmctl)( tid, RES, ARG2, ARG3, ARG5 );
|
|
break;
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,
|
|
"FATAL: unhandled syscall(ipc) %lu\n",
|
|
ARG1 );
|
|
VG_(core_panic)("... bye!\n");
|
|
break; /*NOTREACHED*/
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PRE(sys_semget)
|
|
{
|
|
PRINT("sys_semget ( %ld, %ld, %ld )", SARG1, SARG2, SARG3);
|
|
PRE_REG_READ3(long, "semget", vki_key_t, key, int, nsems, int, semflg);
|
|
}
|
|
|
|
PRE(sys_semop)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_semop ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "semop",
|
|
int, semid, struct sembuf *, sops, unsigned, nsoops);
|
|
ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_semctl)
|
|
{
|
|
switch (ARG3 & ~VKI_IPC_64) {
|
|
case VKI_IPC_INFO:
|
|
case VKI_SEM_INFO:
|
|
PRINT("sys_semctl ( %ld, %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2,
|
|
SARG3, ARG4);
|
|
PRE_REG_READ4(long, "semctl",
|
|
int, semid, int, semnum, int, cmd, struct seminfo *, arg);
|
|
break;
|
|
case VKI_IPC_STAT:
|
|
case VKI_SEM_STAT:
|
|
case VKI_IPC_SET:
|
|
PRINT("sys_semctl ( %ld, %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2,
|
|
SARG3, ARG4);
|
|
PRE_REG_READ4(long, "semctl",
|
|
int, semid, int, semnum, int, cmd, struct semid_ds *, arg);
|
|
break;
|
|
case VKI_GETALL:
|
|
case VKI_SETALL:
|
|
PRINT("sys_semctl ( %ld, %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2,
|
|
SARG3, ARG4);
|
|
PRE_REG_READ4(long, "semctl",
|
|
int, semid, int, semnum, int, cmd, unsigned short *, arg);
|
|
break;
|
|
default:
|
|
PRINT("sys_semctl ( %ld, %ld, %ld )", SARG1, SARG2, SARG3);
|
|
PRE_REG_READ3(long, "semctl",
|
|
int, semid, int, semnum, int, cmd);
|
|
break;
|
|
}
|
|
#ifdef VGP_amd64_linux
|
|
ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3|VKI_IPC_64,ARG4);
|
|
#else
|
|
ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
|
|
#endif
|
|
}
|
|
|
|
POST(sys_semctl)
|
|
{
|
|
#ifdef VGP_amd64_linux
|
|
ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3|VKI_IPC_64,ARG4);
|
|
#else
|
|
ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
|
|
#endif
|
|
}
|
|
|
|
PRE(sys_semtimedop)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_semtimedop ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "semtimedop",
|
|
int, semid, struct sembuf *, sops, unsigned, nsoops,
|
|
struct timespec *, timeout);
|
|
ML_(generic_PRE_sys_semtimedop)(tid, ARG1,ARG2,ARG3,ARG4);
|
|
}
|
|
|
|
PRE(sys_semtimedop_time64)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_semtimedop_time64 ( %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x )", SARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "semtimedop_time64",
|
|
int, semid, struct sembuf *, sops, unsigned, nsoops,
|
|
struct vki_timespec64 *, timeout);
|
|
PRE_MEM_READ( "semtimedop_time64(sops)", ARG1,
|
|
ARG2 * sizeof(struct vki_sembuf) );
|
|
if (ARG3 != 0)
|
|
pre_read_timespec64(tid, "semtimedop_time64(timeout)", ARG3);
|
|
}
|
|
|
|
PRE(sys_msgget)
|
|
{
|
|
PRINT("sys_msgget ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(long, "msgget", vki_key_t, key, int, msgflg);
|
|
}
|
|
|
|
PRE(sys_msgsnd)
|
|
{
|
|
PRINT("sys_msgsnd ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %ld )",
|
|
SARG1, ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(long, "msgsnd",
|
|
int, msqid, struct msgbuf *, msgp, vki_size_t, msgsz, int, msgflg);
|
|
ML_(linux_PRE_sys_msgsnd)(tid, ARG1,ARG2,ARG3,ARG4);
|
|
if ((ARG4 & VKI_IPC_NOWAIT) == 0)
|
|
*flags |= SfMayBlock;
|
|
}
|
|
|
|
PRE(sys_msgrcv)
|
|
{
|
|
PRINT("sys_msgrcv ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %ld, %ld )",
|
|
SARG1, ARG2, ARG3, SARG4, SARG5);
|
|
PRE_REG_READ5(long, "msgrcv",
|
|
int, msqid, struct msgbuf *, msgp, vki_size_t, msgsz,
|
|
long, msgytp, int, msgflg);
|
|
ML_(linux_PRE_sys_msgrcv)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
if ((ARG5 & VKI_IPC_NOWAIT) == 0)
|
|
*flags |= SfMayBlock;
|
|
}
|
|
POST(sys_msgrcv)
|
|
{
|
|
ML_(linux_POST_sys_msgrcv)(tid, RES,ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
PRE(sys_msgctl)
|
|
{
|
|
PRINT("sys_msgctl ( %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3);
|
|
PRE_REG_READ3(long, "msgctl",
|
|
int, msqid, int, cmd, struct msqid_ds *, buf);
|
|
ML_(linux_PRE_sys_msgctl)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
POST(sys_msgctl)
|
|
{
|
|
ML_(linux_POST_sys_msgctl)(tid, RES,ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_shmget)
|
|
{
|
|
PRINT("sys_shmget ( %ld, %" FMT_REGWORD "u, %ld )", SARG1, ARG2, SARG3);
|
|
PRE_REG_READ3(long, "shmget", vki_key_t, key, vki_size_t, size, int, shmflg);
|
|
if (ARG3 & VKI_SHM_HUGETLB) {
|
|
static Bool warning_given = False;
|
|
ARG3 &= ~VKI_SHM_HUGETLB;
|
|
if (!warning_given) {
|
|
warning_given = True;
|
|
VG_(umsg)(
|
|
"WARNING: valgrind ignores shmget(shmflg) SHM_HUGETLB\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_shmat)
|
|
{
|
|
UWord arg2tmp;
|
|
PRINT("sys_shmat ( %ld, %#" FMT_REGWORD "x, %ld )", SARG1, ARG2, SARG3);
|
|
PRE_REG_READ3(long, "shmat",
|
|
int, shmid, const void *, shmaddr, int, shmflg);
|
|
#if defined(VGP_arm_linux)
|
|
/* Round the attach address down to an VKI_SHMLBA boundary if the
|
|
client requested rounding. See #222545. This is necessary only
|
|
on arm-linux because VKI_SHMLBA is 4 * VKI_PAGE size; on all
|
|
other linux targets it is the same as the page size. */
|
|
if (ARG3 & VKI_SHM_RND)
|
|
ARG2 = VG_ROUNDDN(ARG2, VKI_SHMLBA);
|
|
#endif
|
|
arg2tmp = ML_(generic_PRE_sys_shmat)(tid, ARG1,ARG2,ARG3);
|
|
if (arg2tmp == 0)
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
else
|
|
ARG2 = arg2tmp; // used in POST
|
|
}
|
|
|
|
POST(sys_shmat)
|
|
{
|
|
ML_(generic_POST_sys_shmat)(tid, RES,ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_shmdt)
|
|
{
|
|
PRINT("sys_shmdt ( %#" FMT_REGWORD "x )",ARG1);
|
|
PRE_REG_READ1(long, "shmdt", const void *, shmaddr);
|
|
if (!ML_(generic_PRE_sys_shmdt)(tid, ARG1))
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
|
|
POST(sys_shmdt)
|
|
{
|
|
ML_(generic_POST_sys_shmdt)(tid, RES,ARG1);
|
|
}
|
|
|
|
PRE(sys_shmctl)
|
|
{
|
|
PRINT("sys_shmctl ( %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3);
|
|
PRE_REG_READ3(long, "shmctl",
|
|
int, shmid, int, cmd, struct shmid_ds *, buf);
|
|
#if defined(VGP_amd64_linux) || defined(VGP_arm64_linux)
|
|
ML_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2|VKI_IPC_64,ARG3);
|
|
#else
|
|
ML_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2,ARG3);
|
|
#endif
|
|
}
|
|
|
|
POST(sys_shmctl)
|
|
{
|
|
#if defined(VGP_amd64_linux) || defined(VGP_arm64_linux)
|
|
ML_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2|VKI_IPC_64,ARG3);
|
|
#else
|
|
ML_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2,ARG3);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Generic handler for sys_socketcall
|
|
Depending on the platform, some socket related syscalls (e.g. socketpair,
|
|
socket, bind, ...)
|
|
are either direct system calls, or are all implemented via sys_socketcall.
|
|
------------------------------------------------------------------ */
|
|
#ifdef __NR_socketcall
|
|
PRE(sys_socketcall)
|
|
{
|
|
# define ARG2_0 (((UWord*)(Addr)ARG2)[0])
|
|
# define ARG2_1 (((UWord*)(Addr)ARG2)[1])
|
|
# define ARG2_2 (((UWord*)(Addr)ARG2)[2])
|
|
# define ARG2_3 (((UWord*)(Addr)ARG2)[3])
|
|
# define ARG2_4 (((UWord*)(Addr)ARG2)[4])
|
|
# define ARG2_5 (((UWord*)(Addr)ARG2)[5])
|
|
|
|
// call PRE_MEM_READ and check for EFAULT result.
|
|
#define PRE_MEM_READ_ef(msg, arg, size) \
|
|
{ \
|
|
PRE_MEM_READ( msg, arg, size); \
|
|
if (!ML_(valid_client_addr)(arg, size, tid, NULL)) { \
|
|
SET_STATUS_Failure( VKI_EFAULT ); \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_socketcall ( %ld, %#lx )", SARG1, ARG2);
|
|
PRE_REG_READ2(long, "socketcall", int, call, unsigned long *, args);
|
|
|
|
switch (ARG1 /* request */) {
|
|
|
|
case VKI_SYS_SOCKETPAIR:
|
|
/* int socketpair(int d, int type, int protocol, int sv[2]); */
|
|
PRE_MEM_READ_ef( "socketcall.socketpair(args)", ARG2, 4*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_socketpair)( tid, ARG2_0, ARG2_1, ARG2_2, ARG2_3 );
|
|
break;
|
|
|
|
case VKI_SYS_SOCKET:
|
|
/* int socket(int domain, int type, int protocol); */
|
|
PRE_MEM_READ_ef( "socketcall.socket(args)", ARG2, 3*sizeof(Addr) );
|
|
break;
|
|
|
|
case VKI_SYS_BIND:
|
|
/* int bind(int sockfd, struct sockaddr *my_addr,
|
|
int addrlen); */
|
|
PRE_MEM_READ_ef( "socketcall.bind(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_bind)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_LISTEN:
|
|
/* int listen(int s, int backlog); */
|
|
PRE_MEM_READ_ef( "socketcall.listen(args)", ARG2, 2*sizeof(Addr) );
|
|
break;
|
|
|
|
case VKI_SYS_ACCEPT:
|
|
/* int accept(int s, struct sockaddr *addr, int *addrlen); */
|
|
PRE_MEM_READ_ef( "socketcall.accept(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_accept)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_ACCEPT4:
|
|
/* int accept4(int s, struct sockaddr *addr, int *addrlen, int flags); */
|
|
PRE_MEM_READ_ef( "socketcall.accept4(args)", ARG2, 4*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_accept)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_SENDTO:
|
|
/* int sendto(int s, const void *msg, int len,
|
|
unsigned int flags,
|
|
const struct sockaddr *to, int tolen); */
|
|
PRE_MEM_READ_ef( "socketcall.sendto(args)", ARG2, 6*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_sendto)( tid, ARG2_0, ARG2_1, ARG2_2,
|
|
ARG2_3, ARG2_4, ARG2_5 );
|
|
break;
|
|
|
|
case VKI_SYS_SEND:
|
|
/* int send(int s, const void *msg, size_t len, int flags); */
|
|
PRE_MEM_READ_ef( "socketcall.send(args)", ARG2, 4*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_send)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_RECVFROM:
|
|
/* int recvfrom(int s, void *buf, int len, unsigned int flags,
|
|
struct sockaddr *from, int *fromlen); */
|
|
PRE_MEM_READ_ef( "socketcall.recvfrom(args)", ARG2, 6*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_recvfrom)( tid, ARG2_0, ARG2_1, ARG2_2,
|
|
ARG2_3, ARG2_4, ARG2_5 );
|
|
break;
|
|
|
|
case VKI_SYS_RECV:
|
|
/* int recv(int s, void *buf, int len, unsigned int flags); */
|
|
/* man 2 recv says:
|
|
The recv call is normally used only on a connected socket
|
|
(see connect(2)) and is identical to recvfrom with a NULL
|
|
from parameter.
|
|
*/
|
|
PRE_MEM_READ_ef( "socketcall.recv(args)", ARG2, 4*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_recv)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_CONNECT:
|
|
/* int connect(int sockfd,
|
|
struct sockaddr *serv_addr, int addrlen ); */
|
|
PRE_MEM_READ_ef( "socketcall.connect(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_connect)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_SETSOCKOPT:
|
|
/* int setsockopt(int s, int level, int optname,
|
|
const void *optval, int optlen); */
|
|
PRE_MEM_READ_ef( "socketcall.setsockopt(args)", ARG2, 5*sizeof(Addr) );
|
|
ML_(linux_PRE_sys_setsockopt)( tid, ARG2_0, ARG2_1, ARG2_2,
|
|
ARG2_3, ARG2_4 );
|
|
break;
|
|
|
|
case VKI_SYS_GETSOCKOPT:
|
|
/* int getsockopt(int s, int level, int optname,
|
|
void *optval, socklen_t *optlen); */
|
|
PRE_MEM_READ_ef( "socketcall.getsockopt(args)", ARG2, 5*sizeof(Addr) );
|
|
ML_(linux_PRE_sys_getsockopt)( tid, ARG2_0, ARG2_1, ARG2_2,
|
|
ARG2_3, ARG2_4 );
|
|
break;
|
|
|
|
case VKI_SYS_GETSOCKNAME:
|
|
/* int getsockname(int s, struct sockaddr* name, int* namelen) */
|
|
PRE_MEM_READ_ef( "socketcall.getsockname(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_getsockname)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_GETPEERNAME:
|
|
/* int getpeername(int s, struct sockaddr* name, int* namelen) */
|
|
PRE_MEM_READ_ef( "socketcall.getpeername(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_getpeername)( tid, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_SHUTDOWN:
|
|
/* int shutdown(int s, int how); */
|
|
PRE_MEM_READ_ef( "socketcall.shutdown(args)", ARG2, 2*sizeof(Addr) );
|
|
break;
|
|
|
|
case VKI_SYS_SENDMSG:
|
|
/* int sendmsg(int s, const struct msghdr *msg, int flags); */
|
|
PRE_MEM_READ_ef( "socketcall.sendmsg(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_sendmsg)( tid, "msg",
|
|
(struct vki_msghdr *)(Addr)ARG2_1 );
|
|
break;
|
|
|
|
case VKI_SYS_RECVMSG:
|
|
/* int recvmsg(int s, struct msghdr *msg, int flags); */
|
|
PRE_MEM_READ_ef("socketcall.recvmsg(args)", ARG2, 3*sizeof(Addr) );
|
|
ML_(generic_PRE_sys_recvmsg)( tid, "msg",
|
|
(struct vki_msghdr *)(Addr)ARG2_1 );
|
|
break;
|
|
|
|
case VKI_SYS_RECVMMSG:
|
|
/* int recvmmsg(int s, struct mmsghdr *mmsg, int vlen, int flags,
|
|
struct timespec *timeout); */
|
|
PRE_MEM_READ_ef("socketcall.recvmmsg(args)", ARG2, 5*sizeof(Addr) );
|
|
ML_(linux_PRE_sys_recvmmsg)( tid, ARG2_0, ARG2_1, ARG2_2, ARG2_3,
|
|
ARG2_4 );
|
|
break;
|
|
|
|
case VKI_SYS_SENDMMSG:
|
|
/* int sendmmsg(int s, struct mmsghdr *mmsg, int vlen, int flags); */
|
|
PRE_MEM_READ_ef("socketcall.sendmmsg(args)", ARG2, 4*sizeof(Addr) );
|
|
ML_(linux_PRE_sys_sendmmsg)( tid, ARG2_0, ARG2_1, ARG2_2, ARG2_3 );
|
|
break;
|
|
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,"Warning: unhandled socketcall 0x%lx\n",ARG1);
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
break;
|
|
}
|
|
# undef ARG2_0
|
|
# undef ARG2_1
|
|
# undef ARG2_2
|
|
# undef ARG2_3
|
|
# undef ARG2_4
|
|
# undef ARG2_5
|
|
}
|
|
|
|
POST(sys_socketcall)
|
|
{
|
|
# define ARG2_0 (((UWord*)(Addr)ARG2)[0])
|
|
# define ARG2_1 (((UWord*)(Addr)ARG2)[1])
|
|
# define ARG2_2 (((UWord*)(Addr)ARG2)[2])
|
|
# define ARG2_3 (((UWord*)(Addr)ARG2)[3])
|
|
# define ARG2_4 (((UWord*)(Addr)ARG2)[4])
|
|
# define ARG2_5 (((UWord*)(Addr)ARG2)[5])
|
|
|
|
SysRes r;
|
|
vg_assert(SUCCESS);
|
|
switch (ARG1 /* request */) {
|
|
|
|
case VKI_SYS_SOCKETPAIR:
|
|
r = ML_(generic_POST_sys_socketpair)(
|
|
tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1, ARG2_2, ARG2_3
|
|
);
|
|
SET_STATUS_from_SysRes(r);
|
|
break;
|
|
|
|
case VKI_SYS_SOCKET:
|
|
r = ML_(generic_POST_sys_socket)( tid, VG_(mk_SysRes_Success)(RES) );
|
|
SET_STATUS_from_SysRes(r);
|
|
break;
|
|
|
|
case VKI_SYS_BIND:
|
|
/* int bind(int sockfd, struct sockaddr *my_addr,
|
|
int addrlen); */
|
|
break;
|
|
|
|
case VKI_SYS_LISTEN:
|
|
/* int listen(int s, int backlog); */
|
|
break;
|
|
|
|
case VKI_SYS_ACCEPT:
|
|
case VKI_SYS_ACCEPT4:
|
|
/* int accept(int s, struct sockaddr *addr, int *addrlen); */
|
|
/* int accept4(int s, struct sockaddr *addr, int *addrlen, int flags); */
|
|
r = ML_(generic_POST_sys_accept)( tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1, ARG2_2 );
|
|
SET_STATUS_from_SysRes(r);
|
|
break;
|
|
|
|
case VKI_SYS_SENDTO:
|
|
break;
|
|
|
|
case VKI_SYS_SEND:
|
|
break;
|
|
|
|
case VKI_SYS_RECVFROM:
|
|
ML_(generic_POST_sys_recvfrom)( tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1, ARG2_2,
|
|
ARG2_3, ARG2_4, ARG2_5 );
|
|
break;
|
|
|
|
case VKI_SYS_RECV:
|
|
ML_(generic_POST_sys_recv)( tid, RES, ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_CONNECT:
|
|
break;
|
|
|
|
case VKI_SYS_SETSOCKOPT:
|
|
break;
|
|
|
|
case VKI_SYS_GETSOCKOPT:
|
|
ML_(linux_POST_sys_getsockopt)( tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1,
|
|
ARG2_2, ARG2_3, ARG2_4 );
|
|
break;
|
|
|
|
case VKI_SYS_GETSOCKNAME:
|
|
ML_(generic_POST_sys_getsockname)( tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_GETPEERNAME:
|
|
ML_(generic_POST_sys_getpeername)( tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG2_0, ARG2_1, ARG2_2 );
|
|
break;
|
|
|
|
case VKI_SYS_SHUTDOWN:
|
|
break;
|
|
|
|
case VKI_SYS_SENDMSG:
|
|
break;
|
|
|
|
case VKI_SYS_RECVMSG:
|
|
ML_(generic_POST_sys_recvmsg)( tid, "msg",
|
|
(struct vki_msghdr *)(Addr)ARG2_1, RES );
|
|
break;
|
|
|
|
case VKI_SYS_RECVMMSG:
|
|
ML_(linux_POST_sys_recvmmsg)( tid, RES,
|
|
ARG2_0, ARG2_1, ARG2_2, ARG2_3, ARG2_4 );
|
|
break;
|
|
|
|
case VKI_SYS_SENDMMSG:
|
|
ML_(linux_POST_sys_sendmmsg)( tid, RES, ARG2_0, ARG2_1, ARG2_2, ARG2_3 );
|
|
break;
|
|
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,"FATAL: unhandled socketcall 0x%lx\n",ARG1);
|
|
VG_(core_panic)("... bye!\n");
|
|
break; /*NOTREACHED*/
|
|
}
|
|
# undef ARG2_0
|
|
# undef ARG2_1
|
|
# undef ARG2_2
|
|
# undef ARG2_3
|
|
# undef ARG2_4
|
|
# undef ARG2_5
|
|
}
|
|
#endif
|
|
|
|
PRE(sys_socket)
|
|
{
|
|
PRINT("sys_socket ( %ld, %ld, %ld )", SARG1, SARG2, SARG3);
|
|
PRE_REG_READ3(long, "socket", int, domain, int, type, int, protocol);
|
|
}
|
|
POST(sys_socket)
|
|
{
|
|
SysRes r;
|
|
vg_assert(SUCCESS);
|
|
r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES));
|
|
SET_STATUS_from_SysRes(r);
|
|
}
|
|
|
|
PRE(sys_setsockopt)
|
|
{
|
|
PRINT("sys_setsockopt ( %ld, %ld, %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u )", SARG1, SARG2, SARG3, ARG4, ARG5);
|
|
PRE_REG_READ5(long, "setsockopt",
|
|
int, s, int, level, int, optname,
|
|
const void *, optval, unsigned, optlen); // socklen_t
|
|
ML_(linux_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
PRE(sys_getsockopt)
|
|
{
|
|
PRINT("sys_getsockopt ( %ld, %ld, %ld, %#" FMT_REGWORD "x, %ld )",
|
|
SARG1, SARG2, SARG3, ARG4, SARG5);
|
|
PRE_REG_READ5(long, "getsockopt",
|
|
int, s, int, level, int, optname,
|
|
void *, optval, int, *optlen);
|
|
ML_(linux_PRE_sys_getsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
POST(sys_getsockopt)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
ML_(linux_POST_sys_getsockopt)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
PRE(sys_connect)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_connect ( %ld, %#" FMT_REGWORD "x, %ld )", SARG1, ARG2, SARG3);
|
|
PRE_REG_READ3(long, "connect",
|
|
int, sockfd, struct sockaddr *, serv_addr, int, addrlen);
|
|
ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_accept)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_accept ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "accept",
|
|
int, s, struct sockaddr *, addr, int *, addrlen);
|
|
ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
POST(sys_accept)
|
|
{
|
|
SysRes r;
|
|
vg_assert(SUCCESS);
|
|
r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3);
|
|
SET_STATUS_from_SysRes(r);
|
|
}
|
|
|
|
PRE(sys_accept4)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_accept4 ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %ld )",
|
|
SARG1, ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(long, "accept4",
|
|
int, s, struct sockaddr *, addr, int *, addrlen, int, flags);
|
|
ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
POST(sys_accept4)
|
|
{
|
|
SysRes r;
|
|
vg_assert(SUCCESS);
|
|
r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3);
|
|
SET_STATUS_from_SysRes(r);
|
|
}
|
|
|
|
PRE(sys_send)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_send ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x )", SARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "send",
|
|
int, s, const void *, msg, vki_size_t, len,
|
|
int, flags);
|
|
|
|
ML_(generic_PRE_sys_send)( tid, ARG1, ARG2, ARG3 );
|
|
}
|
|
|
|
PRE(sys_sendto)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_sendto ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x, %ld )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, SARG6);
|
|
PRE_REG_READ6(long, "sendto",
|
|
int, s, const void *, msg, vki_size_t, len,
|
|
unsigned int, flags,
|
|
const struct sockaddr *, to, int, tolen);
|
|
ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
|
|
}
|
|
|
|
PRE (sys_recv)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT ("sys_recv ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", SARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4 (long, "recv", int, s, void *, buf, vki_size_t, len,
|
|
unsigned int, flags);
|
|
ML_ (generic_PRE_sys_recv) (tid, ARG1, ARG2, ARG3);
|
|
}
|
|
|
|
POST (sys_recv)
|
|
{
|
|
ML_ (generic_POST_sys_recv) (tid, RES, ARG1, ARG2, ARG3);
|
|
}
|
|
|
|
PRE(sys_recvfrom)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_recvfrom ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(long, "recvfrom",
|
|
int, s, void *, buf, vki_size_t, len, unsigned int, flags,
|
|
struct sockaddr *, from, int *, fromlen);
|
|
ML_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
|
|
}
|
|
POST(sys_recvfrom)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
|
|
}
|
|
|
|
PRE(sys_sendmsg)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_sendmsg ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "sendmsg",
|
|
int, s, const struct msghdr *, msg, unsigned int, flags);
|
|
ML_(generic_PRE_sys_sendmsg)(tid, "msg", (struct vki_msghdr *)(Addr)ARG2);
|
|
}
|
|
|
|
PRE(sys_recvmsg)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_recvmsg ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "recvmsg", int, s, struct msghdr *, msg,
|
|
unsigned int, flags);
|
|
ML_(generic_PRE_sys_recvmsg)(tid, "msg", (struct vki_msghdr *)(Addr)ARG2);
|
|
}
|
|
POST(sys_recvmsg)
|
|
{
|
|
ML_(generic_POST_sys_recvmsg)(tid, "msg", (struct vki_msghdr *)(Addr)ARG2,
|
|
RES);
|
|
}
|
|
|
|
PRE(sys_shutdown)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_shutdown ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(int, "shutdown", int, s, int, how);
|
|
}
|
|
|
|
PRE(sys_bind)
|
|
{
|
|
PRINT("sys_bind ( %ld, %#" FMT_REGWORD "x, %ld )", SARG1, ARG2, SARG3);
|
|
PRE_REG_READ3(long, "bind",
|
|
int, sockfd, struct sockaddr *, my_addr, int, addrlen);
|
|
ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_listen)
|
|
{
|
|
PRINT("sys_listen ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(long, "listen", int, s, int, backlog);
|
|
}
|
|
|
|
PRE(sys_getsockname)
|
|
{
|
|
PRINT("sys_getsockname ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "getsockname",
|
|
int, s, struct sockaddr *, name, int *, namelen);
|
|
ML_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
POST(sys_getsockname)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_getpeername)
|
|
{
|
|
PRINT("sys_getpeername ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "getpeername",
|
|
int, s, struct sockaddr *, name, int *, namelen);
|
|
ML_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3);
|
|
}
|
|
POST(sys_getpeername)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
ML_(generic_POST_sys_getpeername)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3);
|
|
}
|
|
|
|
PRE(sys_socketpair)
|
|
{
|
|
PRINT("sys_socketpair ( %ld, %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2,
|
|
SARG3, ARG4);
|
|
PRE_REG_READ4(long, "socketpair",
|
|
int, d, int, type, int, protocol, int*, sv);
|
|
ML_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4);
|
|
}
|
|
POST(sys_socketpair)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
ML_(generic_POST_sys_socketpair)(tid, VG_(mk_SysRes_Success)(RES),
|
|
ARG1,ARG2,ARG3,ARG4);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
*at wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_openat)
|
|
{
|
|
HChar name[30]; // large enough
|
|
SysRes sres;
|
|
|
|
if (ARG3 & VKI_O_CREAT) {
|
|
// 4-arg version
|
|
PRINT("sys_openat ( %ld, %#" FMT_REGWORD "x(%s), %ld, %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3, SARG4);
|
|
PRE_REG_READ4(long, "openat",
|
|
int, dfd, const char *, filename, int, flags, int, mode);
|
|
} else {
|
|
// 3-arg version
|
|
PRINT("sys_openat ( %ld, %#" FMT_REGWORD "x(%s), %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3);
|
|
PRE_REG_READ3(long, "openat",
|
|
int, dfd, const char *, filename, int, flags);
|
|
}
|
|
|
|
PRE_MEM_RASCIIZ( "openat(filename)", ARG2 );
|
|
|
|
/* For absolute filenames, dfd is ignored. If dfd is AT_FDCWD,
|
|
filename is relative to cwd. When comparing dfd against AT_FDCWD,
|
|
be sure only to compare the bottom 32 bits. */
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& *(Char *)(Addr)ARG2 != '/'
|
|
&& ((Int)ARG1) != ((Int)VKI_AT_FDCWD)
|
|
&& !ML_(fd_allowed)(ARG1, "openat", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
|
|
/* Handle the case where the open is of /proc/self/cmdline or
|
|
/proc/<pid>/cmdline, and just give it a copy of the fd for the
|
|
fake file we cooked up at startup (in m_main). Also, seek the
|
|
cloned fd back to the start. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/cmdline", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/cmdline") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_cmdline_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Do the same for /proc/self/auxv or /proc/<pid>/auxv case. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/auxv") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_auxv_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* And for /proc/self/exe or /proc/<pid>/exe case. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/exe") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_exec_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Otherwise handle normally */
|
|
*flags |= SfMayBlock;
|
|
}
|
|
|
|
POST(sys_openat)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "openat", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)(Addr)ARG2);
|
|
}
|
|
}
|
|
|
|
PRE(sys_mkdirat)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_mkdirat ( %ld, %#" FMT_REGWORD "x(%s), %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3);
|
|
PRE_REG_READ3(long, "mkdirat",
|
|
int, dfd, const char *, pathname, int, mode);
|
|
PRE_MEM_RASCIIZ( "mkdirat(pathname)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_mknodat)
|
|
{
|
|
PRINT("sys_mknodat ( %ld, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x )", SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4 );
|
|
PRE_REG_READ4(long, "mknodat",
|
|
int, dfd, const char *, pathname, int, mode, unsigned, dev);
|
|
PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_fchownat)
|
|
{
|
|
PRINT("sys_fchownat ( %ld, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x )", SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "fchownat",
|
|
int, dfd, const char *, path,
|
|
vki_uid_t, owner, vki_gid_t, group);
|
|
PRE_MEM_RASCIIZ( "fchownat(path)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_futimesat)
|
|
{
|
|
PRINT("sys_futimesat ( %ld, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3);
|
|
PRE_REG_READ3(long, "futimesat",
|
|
int, dfd, char *, filename, struct timeval *, tvp);
|
|
if (ARG2 != 0)
|
|
PRE_MEM_RASCIIZ( "futimesat(filename)", ARG2 );
|
|
if (ARG3 != 0)
|
|
PRE_MEM_READ( "futimesat(tvp)", ARG3, 2 * sizeof(struct vki_timeval) );
|
|
}
|
|
|
|
PRE(sys_utimensat)
|
|
{
|
|
PRINT("sys_utimensat ( %ld, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x )", SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "utimensat",
|
|
int, dfd, char *, filename, struct timespec *, utimes, int, flags);
|
|
if (ARG2 != 0)
|
|
PRE_MEM_RASCIIZ( "utimensat(filename)", ARG2 );
|
|
if (ARG3 != 0) {
|
|
/* If timespec.tv_nsec has the special value UTIME_NOW or UTIME_OMIT
|
|
then the tv_sec field is ignored. */
|
|
struct vki_timespec *times = (struct vki_timespec *)(Addr)ARG3;
|
|
PRE_MEM_READ( "utimensat(times[0].tv_nsec)",
|
|
(Addr)×[0].tv_nsec, sizeof(times[0].tv_nsec));
|
|
PRE_MEM_READ( "utimensat(times[1].tv_nsec)",
|
|
(Addr)×[1].tv_nsec, sizeof(times[1].tv_nsec));
|
|
if (ML_(safe_to_deref)(times, 2 * sizeof(struct vki_timespec))) {
|
|
if (times[0].tv_nsec != VKI_UTIME_NOW
|
|
&& times[0].tv_nsec != VKI_UTIME_OMIT)
|
|
PRE_MEM_READ( "utimensat(times[0].tv_sec)",
|
|
(Addr)×[0].tv_sec, sizeof(times[0].tv_sec));
|
|
if (times[1].tv_nsec != VKI_UTIME_NOW
|
|
&& times[1].tv_nsec != VKI_UTIME_OMIT)
|
|
PRE_MEM_READ( "utimensat(times[1].tv_sec)",
|
|
(Addr)×[1].tv_sec, sizeof(times[1].tv_sec));
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_utimensat_time64)
|
|
{
|
|
PRINT("sys_utimensat_time64 ( %ld, %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x, 0x%" FMT_REGWORD "x )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "utimensat_time64",
|
|
int, dfd, char *, filename, struct timespec *, utimes, int, flags);
|
|
if (ARG2 != 0)
|
|
PRE_MEM_RASCIIZ( "utimensat_time64(filename)", ARG2 );
|
|
if (ARG3 != 0) {
|
|
/* If timespec.tv_nsec has the special value UTIME_NOW or UTIME_OMIT
|
|
then the tv_sec field is ignored. */
|
|
struct vki_timespec64 *times = (struct vki_timespec64 *)(Addr)ARG3;
|
|
PRE_MEM_READ( "utimensat_time64(times[0].tv_nsec)",
|
|
(Addr)×[0].tv_nsec, sizeof(times[0].tv_nsec));
|
|
PRE_MEM_READ( "utimensat_time64(times[1].tv_nsec)",
|
|
(Addr)×[1].tv_nsec, sizeof(times[1].tv_nsec));
|
|
if (ML_(safe_to_deref)(times, 2 * sizeof(struct vki_timespec64))) {
|
|
if (times[0].tv_nsec != VKI_UTIME_NOW
|
|
&& times[0].tv_nsec != VKI_UTIME_OMIT)
|
|
PRE_MEM_READ( "utimensat_time64(times[0].tv_sec)",
|
|
(Addr)×[0].tv_sec, sizeof(times[0].tv_sec));
|
|
if (times[1].tv_nsec != VKI_UTIME_NOW
|
|
&& times[1].tv_nsec != VKI_UTIME_OMIT)
|
|
PRE_MEM_READ( "utimensat_time64(times[1].tv_sec)",
|
|
(Addr)×[1].tv_sec, sizeof(times[1].tv_sec));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !defined(VGP_nanomips_linux)
|
|
PRE(sys_newfstatat)
|
|
{
|
|
FUSE_COMPATIBLE_MAY_BLOCK();
|
|
PRINT("sys_newfstatat ( %ld, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fstatat",
|
|
int, dfd, char *, file_name, struct stat *, buf);
|
|
// See the comment about Rust in PRE(sys_statx). When glibc does support
|
|
// statx rust uses that instead of the system call, but glibc's statx is
|
|
// implemented in terms of fstatat, so the filename being NULL is
|
|
// transferred here.
|
|
if (ARG2 != 0) {
|
|
PRE_MEM_RASCIIZ( "fstatat(file_name)", ARG2 );
|
|
PRE_MEM_WRITE( "fstatat(buf)", ARG3, sizeof(struct vki_stat) );
|
|
}
|
|
}
|
|
|
|
POST(sys_newfstatat)
|
|
{
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_stat) );
|
|
}
|
|
#endif
|
|
|
|
PRE(sys_unlinkat)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_unlinkat ( %ld, %#" FMT_REGWORD "x(%s) )", SARG1, ARG2,
|
|
(HChar*)(Addr)ARG2);
|
|
PRE_REG_READ2(long, "unlinkat", int, dfd, const char *, pathname);
|
|
PRE_MEM_RASCIIZ( "unlinkat(pathname)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_renameat)
|
|
{
|
|
PRINT("sys_renameat ( %ld, %#" FMT_REGWORD "x(%s), %ld, %#"
|
|
FMT_REGWORD "x(%s) )", SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3,
|
|
ARG4, (HChar*)(Addr)ARG4);
|
|
PRE_REG_READ4(long, "renameat",
|
|
int, olddfd, const char *, oldpath,
|
|
int, newdfd, const char *, newpath);
|
|
PRE_MEM_RASCIIZ( "renameat(oldpath)", ARG2 );
|
|
PRE_MEM_RASCIIZ( "renameat(newpath)", ARG4 );
|
|
}
|
|
|
|
PRE(sys_renameat2)
|
|
{
|
|
PRINT("sys_renameat2 ( %ld, %#" FMT_REGWORD "x(%s), %ld, %#" FMT_REGWORD
|
|
"x(%s), %" FMT_REGWORD "u )", SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3,
|
|
ARG4, (HChar*)(Addr)ARG4, ARG5);
|
|
PRE_REG_READ5(long, "renameat2",
|
|
int, olddfd, const char *, oldpath,
|
|
int, newdfd, const char *, newpath,
|
|
unsigned int, flags);
|
|
PRE_MEM_RASCIIZ( "renameat2(oldpath)", ARG2 );
|
|
PRE_MEM_RASCIIZ( "renameat2(newpath)", ARG4 );
|
|
}
|
|
|
|
PRE(sys_linkat)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_linkat ( %ld, %#" FMT_REGWORD "x(%s), %ld, %#" FMT_REGWORD
|
|
"x(%s), %ld )", SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3, ARG4,
|
|
(HChar*)(Addr)ARG4, SARG5);
|
|
PRE_REG_READ5(long, "linkat",
|
|
int, olddfd, const char *, oldpath,
|
|
int, newdfd, const char *, newpath,
|
|
int, flags);
|
|
PRE_MEM_RASCIIZ( "linkat(oldpath)", ARG2);
|
|
PRE_MEM_RASCIIZ( "linkat(newpath)", ARG4);
|
|
}
|
|
|
|
PRE(sys_symlinkat)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_symlinkat ( %#" FMT_REGWORD "x(%s), %ld, %#" FMT_REGWORD
|
|
"x(%s) )", ARG1, (HChar*)(Addr)ARG1, SARG2, ARG3, (HChar*)(Addr)ARG3);
|
|
PRE_REG_READ3(long, "symlinkat",
|
|
const char *, oldpath, int, newdfd, const char *, newpath);
|
|
PRE_MEM_RASCIIZ( "symlinkat(oldpath)", ARG1 );
|
|
PRE_MEM_RASCIIZ( "symlinkat(newpath)", ARG3 );
|
|
}
|
|
|
|
PRE(sys_readlinkat)
|
|
{
|
|
HChar name[30]; // large enough
|
|
Word saved = SYSNO;
|
|
|
|
PRINT("sys_readlinkat ( %ld, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "readlinkat",
|
|
int, dfd, const char *, path, char *, buf, vki_size_t, bufsiz);
|
|
PRE_MEM_RASCIIZ( "readlinkat(path)", ARG2 );
|
|
PRE_MEM_WRITE( "readlinkat(buf)", ARG3,ARG4 );
|
|
|
|
/*
|
|
* Handle the case where readlinkat is looking at /proc/self/exe or
|
|
* /proc/<pid>/exe.
|
|
*/
|
|
VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
|
|
if (ML_(safe_to_deref)((void*)(Addr)ARG2, 1)
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/exe") == 0)) {
|
|
VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd));
|
|
SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, (UWord)name,
|
|
ARG3, ARG4));
|
|
} else {
|
|
/* Normal case */
|
|
SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, ARG2, ARG3, ARG4));
|
|
}
|
|
|
|
if (SUCCESS && RES > 0)
|
|
POST_MEM_WRITE( ARG3, RES );
|
|
}
|
|
|
|
PRE(sys_fchmodat)
|
|
{
|
|
PRINT("sys_fchmodat ( %ld, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fchmodat",
|
|
int, dfd, const char *, path, vki_mode_t, mode);
|
|
PRE_MEM_RASCIIZ( "fchmodat(path)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_faccessat)
|
|
{
|
|
PRINT("sys_faccessat ( %ld, %#" FMT_REGWORD "x(%s), %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3);
|
|
PRE_REG_READ3(long, "faccessat",
|
|
int, dfd, const char *, pathname, int, mode);
|
|
PRE_MEM_RASCIIZ( "faccessat(pathname)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_faccessat2)
|
|
{
|
|
PRINT("sys_faccessat2 ( %ld, %#" FMT_REGWORD "x(%s), %ld, %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, SARG3, SARG4);
|
|
PRE_REG_READ4(long, "faccessat2",
|
|
int, dfd, const char *, pathname, int, mode, int, flags);
|
|
PRE_MEM_RASCIIZ( "faccessat2(pathname)", ARG2 );
|
|
}
|
|
|
|
PRE(sys_name_to_handle_at)
|
|
{
|
|
PRINT("sys_name_to_handle_at ( %ld, %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x, %#" FMT_REGWORD "x, %ld )", SARG1, ARG2,
|
|
(HChar*)(Addr)ARG2, ARG3, ARG4, SARG5);
|
|
PRE_REG_READ5(int, "name_to_handle_at",
|
|
int, dfd, const char *, name,
|
|
struct vki_file_handle *, handle,
|
|
int *, mnt_id, int, flag);
|
|
PRE_MEM_RASCIIZ( "name_to_handle_at(name)", ARG2 );
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG3, sizeof(struct vki_file_handle))) {
|
|
struct vki_file_handle *fh = (struct vki_file_handle *)(Addr)ARG3;
|
|
PRE_MEM_READ( "name_to_handle_at(handle)", (Addr)&fh->handle_bytes, sizeof(fh->handle_bytes) );
|
|
PRE_MEM_WRITE( "name_to_handle_at(handle)", (Addr)fh, sizeof(struct vki_file_handle) + fh->handle_bytes );
|
|
}
|
|
PRE_MEM_WRITE( "name_to_handle_at(mnt_id)", ARG4, sizeof(int) );
|
|
}
|
|
|
|
POST(sys_name_to_handle_at)
|
|
{
|
|
struct vki_file_handle *fh = (struct vki_file_handle *)(Addr)ARG3;
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_file_handle) + fh->handle_bytes );
|
|
POST_MEM_WRITE( ARG4, sizeof(int) );
|
|
}
|
|
|
|
PRE(sys_open_by_handle_at)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_open_by_handle_at ( %ld, %#" FMT_REGWORD "x, %ld )", SARG1,
|
|
ARG2, SARG3);
|
|
PRE_REG_READ3(int, "open_by_handle_at",
|
|
int, mountdirfd,
|
|
struct vki_file_handle *, handle,
|
|
int, flags);
|
|
PRE_MEM_READ( "open_by_handle_at(handle)", ARG2,
|
|
sizeof(struct vki_file_handle) +
|
|
((struct vki_file_handle*)(Addr)ARG2)->handle_bytes);
|
|
}
|
|
|
|
POST(sys_open_by_handle_at)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "open_by_handle_at", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)(Addr)ARG2);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
p{read,write}v wrappers
|
|
------------------------------------------------------------------ */
|
|
/* This handles the common part of the PRE macro for preadv and preadv2. */
|
|
void handle_pre_sys_preadv(ThreadId tid, SyscallStatus* status,
|
|
Int fd, Addr vector, Int count, const char *str)
|
|
{
|
|
struct vki_iovec * vec;
|
|
Int i;
|
|
/* safe size for the "preadv/preadv2(vector[i])" string */
|
|
char tmp[30];
|
|
|
|
if (!ML_(fd_allowed)(fd, str, tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else if (count > 0) {
|
|
VG_(strcpy) (tmp, str);
|
|
VG_(strcat) (tmp, "(vector)");
|
|
PRE_MEM_READ( tmp, vector, count * sizeof(struct vki_iovec) );
|
|
|
|
if (ML_(safe_to_deref) ((void *)(Addr)vector,
|
|
count * sizeof(struct vki_iovec))) {
|
|
vec = (struct vki_iovec *)(Addr)vector;
|
|
for (i = 0; i < count; i++) {
|
|
/* Note: building such a dynamic error string is *not*
|
|
a pattern to follow. See bug 417075. */
|
|
VG_(snprintf) (tmp, 30, "%s(vector[%d])", str, i);
|
|
PRE_MEM_WRITE( tmp, (Addr)vec[i].iov_base, vec[i].iov_len );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This handles the common part of the POST macro for preadv and preadv2. */
|
|
void handle_post_sys_preadv(ThreadId tid, SyscallStatus* status, Addr vector, Int count)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES > 0) {
|
|
Int i;
|
|
struct vki_iovec * vec = (struct vki_iovec *)(Addr)vector;
|
|
Int remains = RES;
|
|
|
|
/* RES holds the number of bytes read. */
|
|
for (i = 0; i < count; i++) {
|
|
Int nReadThisBuf = vec[i].iov_len;
|
|
if (nReadThisBuf > remains) nReadThisBuf = remains;
|
|
POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
|
|
remains -= nReadThisBuf;
|
|
if (remains < 0) VG_(core_panic)("preadv: remains < 0");
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_preadv)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
const char *str = "preadv";
|
|
#if VG_WORDSIZE == 4
|
|
/* Note that the offset argument here is in lo+hi order on both
|
|
big and little endian platforms... */
|
|
PRINT("sys_preadv ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %lld )",
|
|
ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5));
|
|
PRE_REG_READ5(ssize_t, "preadv",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, vki_u32, offset_low,
|
|
vki_u32, offset_high);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_preadv ( %lu, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(ssize_t, "preadv",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, Word, offset);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
Int fd = ARG1;
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_pre_sys_preadv(tid, status, fd, vector, count, str);
|
|
|
|
}
|
|
|
|
POST(sys_preadv)
|
|
{
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_post_sys_preadv(tid, status, vector, count);
|
|
}
|
|
|
|
PRE(sys_preadv2)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
const char *str = "preadv2";
|
|
#if VG_WORDSIZE == 4
|
|
/* Note that the offset argument here is in lo+hi order on both
|
|
big and little endian platforms... */
|
|
PRINT("sys_preadv2 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %lld, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5), ARG6);
|
|
PRE_REG_READ6(ssize_t, "preadv2",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, vki_u32, offset_low,
|
|
vki_u32, offset_high, unsigned long, flags);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_preadv2 ( %lu, %#lx, %lu, %ld, %lu )", ARG1, ARG2, ARG3, SARG4, ARG5);
|
|
PRE_REG_READ5(ssize_t, "preadv2",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, Word, offset, unsigned long, flags);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
Int fd = ARG1;
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_pre_sys_preadv(tid, status, fd, vector, count, str);
|
|
}
|
|
|
|
POST(sys_preadv2)
|
|
{
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_post_sys_preadv(tid, status, vector, count);
|
|
}
|
|
|
|
/* This handles the common part of the PRE macro for pwritev and pwritev2. */
|
|
void handle_sys_pwritev(ThreadId tid, SyscallStatus* status,
|
|
Int fd, Addr vector, Int count, const char *str)
|
|
{
|
|
Int i;
|
|
struct vki_iovec * vec;
|
|
/* safe size for the "preadv/preadv2(vector[i])" string */
|
|
char tmp[30];
|
|
|
|
if (!ML_(fd_allowed)(fd, str, tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else if (count > 0) {
|
|
VG_(strcpy) (tmp, str);
|
|
VG_(strcat) (tmp, "(vector)");
|
|
PRE_MEM_READ( tmp, vector, count * sizeof(struct vki_iovec) );
|
|
if (ML_(safe_to_deref) ((void *)(Addr)vector,
|
|
count * sizeof(struct vki_iovec))) {
|
|
vec = (struct vki_iovec *)(Addr)vector;
|
|
for (i = 0; i < count; i++) {
|
|
/* Note: building such a dynamic error string is *not*
|
|
a pattern to follow. See bug 417075. */
|
|
VG_(snprintf) (tmp, 30, "%s(vector[%d])", str, i);
|
|
PRE_MEM_READ( tmp, (Addr)vec[i].iov_base, vec[i].iov_len );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PRE(sys_pwritev)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
const char *str = "pwritev";
|
|
#if VG_WORDSIZE == 4
|
|
/* Note that the offset argument here is in lo+hi order on both
|
|
big and little endian platforms... */
|
|
PRINT("sys_pwritev ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %lld )", ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5));
|
|
PRE_REG_READ5(ssize_t, "pwritev",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, vki_u32, offset_low,
|
|
vki_u32, offset_high);
|
|
#elif VG_WORDSIZE == 8
|
|
PRINT("sys_pwritev ( %lu, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(ssize_t, "pwritev",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, Word, offset);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
Int fd = ARG1;
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_sys_pwritev(tid, status, fd, vector, count, str);
|
|
}
|
|
|
|
PRE(sys_pwritev2)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
const char *str = "pwritev2";
|
|
#if VG_WORDSIZE == 4
|
|
/* Note that the offset argument here is in lo+hi order on both
|
|
big and little endian platforms... */
|
|
PRINT("sys_pwritev2 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %lld, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5), ARG6);
|
|
PRE_REG_READ6(ssize_t, "pwritev2",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, vki_u32, offset_low,
|
|
vki_u32, offset_high, unsigned long, flags);
|
|
#elif VG_WORDSIZE == 8
|
|
/* Note offset_high isn't actually used? */
|
|
PRE_REG_READ6(ssize_t, "pwritev2",
|
|
unsigned long, fd, const struct iovec *, vector,
|
|
unsigned long, count, Word, offset,
|
|
Word, offset_high, unsigned long, flags);
|
|
#else
|
|
# error Unexpected word size
|
|
#endif
|
|
Int fd = ARG1;
|
|
Addr vector = ARG2;
|
|
Int count = ARG3;
|
|
|
|
handle_sys_pwritev(tid, status, fd, vector, count, str);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
process_vm_{read,write}v wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_process_vm_readv)
|
|
{
|
|
PRINT("sys_process_vm_readv ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(ssize_t, "process_vm_readv",
|
|
vki_pid_t, pid,
|
|
const struct iovec *, lvec,
|
|
unsigned long, liovcnt,
|
|
const struct iovec *, rvec,
|
|
unsigned long, riovcnt,
|
|
unsigned long, flags);
|
|
PRE_MEM_READ( "process_vm_readv(lvec)",
|
|
ARG2, ARG3 * sizeof(struct vki_iovec) );
|
|
PRE_MEM_READ( "process_vm_readv(rvec)",
|
|
ARG4, ARG5 * sizeof(struct vki_iovec) );
|
|
if (ARG2 != 0
|
|
&& ML_(safe_to_deref) ((void *)(Addr)ARG2,
|
|
sizeof(struct vki_iovec) * ARG3)) {
|
|
const struct vki_iovec *vec = (const struct vki_iovec *)(Addr)ARG2;
|
|
UInt i;
|
|
for (i = 0; i < ARG3; i++)
|
|
PRE_MEM_WRITE( "process_vm_readv(lvec[...])",
|
|
(Addr)vec[i].iov_base, vec[i].iov_len );
|
|
}
|
|
}
|
|
|
|
POST(sys_process_vm_readv)
|
|
{
|
|
const struct vki_iovec *vec = (const struct vki_iovec *)(Addr)ARG2;
|
|
UInt remains = RES;
|
|
UInt i;
|
|
for (i = 0; i < ARG3; i++) {
|
|
UInt nReadThisBuf = vec[i].iov_len <= remains ?
|
|
vec[i].iov_len : remains;
|
|
POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
|
|
remains -= nReadThisBuf;
|
|
}
|
|
}
|
|
|
|
PRE(sys_process_vm_writev)
|
|
{
|
|
PRINT("sys_process_vm_writev ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
|
|
SARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(ssize_t, "process_vm_writev",
|
|
vki_pid_t, pid,
|
|
const struct iovec *, lvec,
|
|
unsigned long, liovcnt,
|
|
const struct iovec *, rvec,
|
|
unsigned long, riovcnt,
|
|
unsigned long, flags);
|
|
PRE_MEM_READ( "process_vm_writev(lvec)",
|
|
ARG2, ARG3 * sizeof(struct vki_iovec) );
|
|
PRE_MEM_READ( "process_vm_writev(rvec)",
|
|
ARG4, ARG5 * sizeof(struct vki_iovec) );
|
|
if (ARG2 != 0
|
|
&& ML_(safe_to_deref) ((void *)(Addr)ARG2,
|
|
sizeof(struct vki_iovec) * ARG3)) {
|
|
const struct vki_iovec *vec = (const struct vki_iovec *)(Addr)ARG2;
|
|
UInt i;
|
|
for (i = 0; i < ARG3; i++)
|
|
PRE_MEM_READ( "process_vm_writev(lvec[...])",
|
|
(Addr)vec[i].iov_base, vec[i].iov_len );
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
{send,recv}mmsg wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_sendmmsg)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_sendmmsg ( %ld, %#" FMT_REGWORD "x, %ld, %ld )", SARG1, ARG2,
|
|
SARG3, SARG4);
|
|
PRE_REG_READ4(long, "sendmmsg",
|
|
int, s, const struct mmsghdr *, mmsg, int, vlen, int, flags);
|
|
ML_(linux_PRE_sys_sendmmsg)(tid, ARG1,ARG2,ARG3,ARG4);
|
|
}
|
|
|
|
POST(sys_sendmmsg)
|
|
{
|
|
ML_(linux_POST_sys_sendmmsg) (tid, RES, ARG1,ARG2,ARG3,ARG4);
|
|
}
|
|
|
|
PRE(sys_recvmmsg)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_recvmmsg ( %ld, %#" FMT_REGWORD "x, %ld, %ld, %#"
|
|
FMT_REGWORD "x )",
|
|
SARG1, ARG2, SARG3, SARG4, ARG5);
|
|
PRE_REG_READ5(long, "recvmmsg",
|
|
int, s, struct mmsghdr *, mmsg, int, vlen,
|
|
int, flags, struct timespec *, timeout);
|
|
ML_(linux_PRE_sys_recvmmsg)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
POST(sys_recvmmsg)
|
|
{
|
|
ML_(linux_POST_sys_recvmmsg) (tid, RES, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
PRE(sys_recvmmsg_time64)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_recvmmsg_time64 ( %ld, %#" FMT_REGWORD "x, %ld, %ld, %#"
|
|
FMT_REGWORD "x )",
|
|
SARG1, ARG2, SARG3, SARG4, ARG5);
|
|
PRE_REG_READ5(long, "recvmmsg_time64",
|
|
int, s, struct mmsghdr *, mmsg, int, vlen,
|
|
int, flags, struct vki_timespec64 *, timeout);
|
|
struct vki_mmsghdr *mmsg = (struct vki_mmsghdr *)ARG2;
|
|
HChar name[40]; // large enough
|
|
UInt i;
|
|
for (i = 0; i < ARG3; i++) {
|
|
VG_(sprintf)(name, "mmsg[%u].msg_hdr", i);
|
|
ML_(generic_PRE_sys_recvmsg)(tid, name, &mmsg[i].msg_hdr);
|
|
VG_(sprintf)(name, "recvmmsg(mmsg[%u].msg_len)", i);
|
|
PRE_MEM_WRITE( name, (Addr)&mmsg[i].msg_len, sizeof(mmsg[i].msg_len) );
|
|
}
|
|
if (ARG5)
|
|
pre_read_timespec64(tid, "recvmmsg(timeout)", ARG5);
|
|
}
|
|
|
|
POST(sys_recvmmsg_time64)
|
|
{
|
|
/* ARG5 isn't actually used, so just use the generic POST. */
|
|
ML_(linux_POST_sys_recvmmsg) (tid, RES, ARG1,ARG2,ARG3,ARG4,ARG5);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
key retention service wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_request_key)
|
|
{
|
|
PRINT("sys_request_key ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x(%s), %ld )", ARG1, (HChar*)(Addr)ARG1, ARG2,
|
|
(HChar*)(Addr)ARG2, ARG3, (HChar*)(Addr)ARG3, SARG4);
|
|
PRE_REG_READ4(long, "request_key",
|
|
const char *, type, const char *, description,
|
|
const char *, callout_info, vki_key_serial_t, keyring);
|
|
PRE_MEM_RASCIIZ( "request_key(type)", ARG1);
|
|
PRE_MEM_RASCIIZ( "request_key(description)", ARG2);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_RASCIIZ( "request_key(callout_info)", ARG3);
|
|
}
|
|
|
|
PRE(sys_add_key)
|
|
{
|
|
PRINT("sys_add_key ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u, %ld )", ARG1, (HChar*)(Addr)ARG1,
|
|
ARG2, (HChar*)(Addr)ARG2, ARG3, ARG4, SARG5);
|
|
PRE_REG_READ5(long, "add_key",
|
|
const char *, type, const char *, description,
|
|
const void *, payload, vki_size_t, plen,
|
|
vki_key_serial_t, keyring);
|
|
PRE_MEM_RASCIIZ( "add_key(type)", ARG1);
|
|
PRE_MEM_RASCIIZ( "add_key(description)", ARG2);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_READ( "request_key(payload)", ARG3, ARG4);
|
|
}
|
|
|
|
PRE(sys_keyctl)
|
|
{
|
|
switch (ARG1 /* option */) {
|
|
case VKI_KEYCTL_GET_KEYRING_ID:
|
|
PRINT("sys_keyctl ( KEYCTL_GET_KEYRING_ID, %ld, %ld )", SARG2, SARG3);
|
|
PRE_REG_READ3(long, "keyctl(KEYCTL_GET_KEYRING_ID)",
|
|
int, option, vki_key_serial_t, id, int, create);
|
|
break;
|
|
case VKI_KEYCTL_JOIN_SESSION_KEYRING:
|
|
PRINT("sys_keyctl ( KEYCTL_JOIN_SESSION_KEYRING, %#" FMT_REGWORD
|
|
"x(%s) )", ARG2,(char*)(Addr)ARG2);
|
|
PRE_REG_READ2(long, "keyctl(KEYCTL_JOIN_SESSION_KEYRING)",
|
|
int, option, const char *, name);
|
|
if (ARG2 != (UWord)NULL)
|
|
PRE_MEM_RASCIIZ("keyctl(KEYCTL_JOIN_SESSION_KEYRING, name)", ARG2);
|
|
break;
|
|
case VKI_KEYCTL_UPDATE:
|
|
PRINT("sys_keyctl ( KEYCTL_UPDATE, %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "keyctl(KEYCTL_UPDATE)",
|
|
int, option, vki_key_serial_t, key,
|
|
const void *, payload, vki_size_t, plen);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_READ("keyctl(KEYCTL_UPDATE, payload)", ARG3, ARG4);
|
|
break;
|
|
case VKI_KEYCTL_REVOKE:
|
|
PRINT("sys_keyctl ( KEYCTL_REVOKE, %ld )", SARG2);
|
|
PRE_REG_READ2(long, "keyctl(KEYCTL_REVOKE)",
|
|
int, option, vki_key_serial_t, id);
|
|
break;
|
|
case VKI_KEYCTL_CHOWN:
|
|
PRINT("sys_keyctl ( KEYCTL_CHOWN, %ld, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "keyctl(KEYCTL_CHOWN)",
|
|
int, option, vki_key_serial_t, id,
|
|
vki_uid_t, uid, vki_gid_t, gid);
|
|
break;
|
|
case VKI_KEYCTL_SETPERM:
|
|
PRINT("sys_keyctl ( KEYCTL_SETPERM, %ld, %" FMT_REGWORD "u )",
|
|
SARG2, ARG3);
|
|
PRE_REG_READ3(long, "keyctl(KEYCTL_SETPERM)",
|
|
int, option, vki_key_serial_t, id, vki_key_perm_t, perm);
|
|
break;
|
|
case VKI_KEYCTL_DESCRIBE:
|
|
PRINT("sys_keyctl ( KEYCTL_DESCRIBE, %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u )", SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "keyctl(KEYCTL_DESCRIBE)",
|
|
int, option, vki_key_serial_t, id,
|
|
char *, buffer, vki_size_t, buflen);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_WRITE("keyctl(KEYCTL_DESCRIBE, buffer)", ARG3, ARG4);
|
|
break;
|
|
case VKI_KEYCTL_CLEAR:
|
|
PRINT("sys_keyctl ( KEYCTL_CLEAR, %ld )", SARG2);
|
|
PRE_REG_READ2(long, "keyctl(KEYCTL_CLEAR)",
|
|
int, option, vki_key_serial_t, keyring);
|
|
break;
|
|
case VKI_KEYCTL_LINK:
|
|
PRINT("sys_keyctl ( KEYCTL_LINK, %ld, %ld )", SARG2, SARG3);
|
|
PRE_REG_READ3(long, "keyctl(KEYCTL_LINK)", int, option,
|
|
vki_key_serial_t, keyring, vki_key_serial_t, key);
|
|
break;
|
|
case VKI_KEYCTL_UNLINK:
|
|
PRINT("sys_keyctl ( KEYCTL_UNLINK, %ld, %ld )", SARG2, SARG3);
|
|
PRE_REG_READ3(long, "keyctl(KEYCTL_UNLINK)", int, option,
|
|
vki_key_serial_t, keyring, vki_key_serial_t, key);
|
|
break;
|
|
case VKI_KEYCTL_SEARCH:
|
|
PRINT("sys_keyctl ( KEYCTL_SEARCH, %ld, %#" FMT_REGWORD "x(%s), %#"
|
|
FMT_REGWORD "x(%s), %ld )", SARG2, ARG3, (HChar*)(Addr)ARG3,
|
|
ARG4, (HChar*)(Addr)ARG4, SARG5);
|
|
PRE_REG_READ5(long, "keyctl(KEYCTL_SEARCH)",
|
|
int, option, vki_key_serial_t, keyring,
|
|
const char *, type, const char *, description,
|
|
vki_key_serial_t, destring);
|
|
PRE_MEM_RASCIIZ("sys_keyctl(KEYCTL_SEARCH, type)", ARG3);
|
|
PRE_MEM_RASCIIZ("sys_keyctl(KEYCTL_SEARCH, description)", ARG4);
|
|
break;
|
|
case VKI_KEYCTL_READ:
|
|
PRINT("sys_keyctl ( KEYCTL_READ, %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD
|
|
"u )", SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "keyctl(KEYCTL_READ)",
|
|
int, option, vki_key_serial_t, keyring,
|
|
char *, buffer, vki_size_t, buflen);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_WRITE("keyctl(KEYCTL_READ, buffer)", ARG3, ARG4);
|
|
break;
|
|
case VKI_KEYCTL_INSTANTIATE:
|
|
PRINT("sys_keyctl ( KEYCTL_INSTANTIATE, %ld, %#" FMT_REGWORD "x, %"
|
|
FMT_REGWORD "u, %ld )", SARG2, ARG3, ARG4, SARG5);
|
|
PRE_REG_READ5(long, "keyctl(KEYCTL_INSTANTIATE)",
|
|
int, option, vki_key_serial_t, key,
|
|
char *, payload, vki_size_t, plen,
|
|
vki_key_serial_t, keyring);
|
|
if (ARG3 != (UWord)NULL)
|
|
PRE_MEM_READ("keyctl(KEYCTL_INSTANTIATE, payload)", ARG3, ARG4);
|
|
break;
|
|
case VKI_KEYCTL_NEGATE:
|
|
PRINT("sys_keyctl ( KEYCTL_NEGATE, %ld, %" FMT_REGWORD "u, %ld )",
|
|
SARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(long, "keyctl(KEYCTL_NEGATE)",
|
|
int, option, vki_key_serial_t, key,
|
|
unsigned, timeout, vki_key_serial_t, keyring);
|
|
break;
|
|
case VKI_KEYCTL_SET_REQKEY_KEYRING:
|
|
PRINT("sys_keyctl ( KEYCTL_SET_REQKEY_KEYRING, %ld )", SARG2);
|
|
PRE_REG_READ2(long, "keyctl(KEYCTL_SET_REQKEY_KEYRING)",
|
|
int, option, int, reqkey_defl);
|
|
break;
|
|
case VKI_KEYCTL_SET_TIMEOUT:
|
|
PRINT("sys_keyctl ( KEYCTL_SET_TIMEOUT, %ld, %" FMT_REGWORD "u )",
|
|
SARG2, ARG3);
|
|
PRE_REG_READ3(long, "keyctl(KEYCTL_SET_TIMEOUT)",
|
|
int, option, vki_key_serial_t, key, unsigned, timeout);
|
|
break;
|
|
case VKI_KEYCTL_ASSUME_AUTHORITY:
|
|
PRINT("sys_keyctl ( KEYCTL_ASSUME_AUTHORITY, %ld )", SARG2);
|
|
PRE_REG_READ2(long, "keyctl(KEYCTL_ASSUME_AUTHORITY)",
|
|
int, option, vki_key_serial_t, key);
|
|
break;
|
|
default:
|
|
PRINT("sys_keyctl ( %ld ) ", SARG1);
|
|
PRE_REG_READ1(long, "keyctl", int, option);
|
|
break;
|
|
}
|
|
}
|
|
|
|
POST(sys_keyctl)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
switch (ARG1 /* option */) {
|
|
case VKI_KEYCTL_DESCRIBE:
|
|
case VKI_KEYCTL_READ:
|
|
if (RES > ARG4)
|
|
POST_MEM_WRITE(ARG3, ARG4);
|
|
else
|
|
POST_MEM_WRITE(ARG3, RES);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
ioprio_ wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_ioprio_set)
|
|
{
|
|
PRINT("sys_ioprio_set ( %ld, %ld, %ld )", SARG1, SARG2, SARG3);
|
|
PRE_REG_READ3(int, "ioprio_set", int, which, int, who, int, ioprio);
|
|
}
|
|
|
|
PRE(sys_ioprio_get)
|
|
{
|
|
PRINT("sys_ioprio_get ( %ld, %ld )", SARG1, SARG2);
|
|
PRE_REG_READ2(int, "ioprio_get", int, which, int, who);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
_module wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_init_module)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_init_module ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#"
|
|
FMT_REGWORD "x(\"%s\") )", ARG1, ARG2, ARG3, (HChar*)(Addr)ARG3);
|
|
PRE_REG_READ3(long, "init_module",
|
|
void *, umod, unsigned long, len, const char *, uargs);
|
|
PRE_MEM_READ( "init_module(umod)", ARG1, ARG2 );
|
|
PRE_MEM_RASCIIZ( "init_module(uargs)", ARG3 );
|
|
}
|
|
|
|
PRE(sys_finit_module)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
|
|
PRINT("sys_finit_module ( %" FMT_REGWORD "x, %#" FMT_REGWORD "x(\"%s\"), %"
|
|
FMT_REGWORD "x )", ARG1, ARG2, (HChar*)(Addr)ARG2, ARG3);
|
|
PRE_REG_READ3(long, "finit_module",
|
|
int, fd, const char *, params, int, flags);
|
|
PRE_MEM_RASCIIZ("finit_module(params)", ARG2);
|
|
}
|
|
|
|
PRE(sys_delete_module)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_delete_module ( %#" FMT_REGWORD "x(\"%s\"), 0x%" FMT_REGWORD
|
|
"x )", ARG1, (HChar*)(Addr)ARG1, ARG2);
|
|
PRE_REG_READ2(long, "delete_module",
|
|
const char *, name_user, unsigned int, flags);
|
|
PRE_MEM_RASCIIZ("delete_module(name_user)", ARG1);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
splice wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_splice)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_splice ( %ld, %#" FMT_REGWORD "x, %ld, %#"
|
|
FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1, ARG2, SARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(vki_ssize_t, "splice",
|
|
int, fd_in, vki_loff_t *, off_in,
|
|
int, fd_out, vki_loff_t *, off_out,
|
|
vki_size_t, len, unsigned int, flags);
|
|
if (!ML_(fd_allowed)(ARG1, "splice(fd_in)", tid, False) ||
|
|
!ML_(fd_allowed)(ARG3, "splice(fd_out)", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
if (ARG2 != 0)
|
|
PRE_MEM_READ( "splice(off_in)", ARG2, sizeof(vki_loff_t));
|
|
if (ARG4 != 0)
|
|
PRE_MEM_READ( "splice(off_out)", ARG4, sizeof(vki_loff_t));
|
|
}
|
|
}
|
|
|
|
PRE(sys_tee)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_tree ( %ld, %ld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
|
|
SARG1, SARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(vki_ssize_t, "tee",
|
|
int, fd_in, int, fd_out,
|
|
vki_size_t, len, unsigned int, flags);
|
|
if (!ML_(fd_allowed)(ARG1, "tee(fd_in)", tid, False) ||
|
|
!ML_(fd_allowed)(ARG2, "tee(fd_out)", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
}
|
|
}
|
|
|
|
PRE(sys_vmsplice)
|
|
{
|
|
Int fdfl;
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_vmsplice ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", SARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(vki_ssize_t, "splice",
|
|
int, fd, struct vki_iovec *, iov,
|
|
unsigned long, nr_segs, unsigned int, flags);
|
|
if (!ML_(fd_allowed)(ARG1, "vmsplice(fd)", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else if ((fdfl = VG_(fcntl)(ARG1, VKI_F_GETFL, 0)) < 0) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
const struct vki_iovec *iov;
|
|
PRE_MEM_READ( "vmsplice(iov)", ARG2, sizeof(struct vki_iovec) * ARG3 );
|
|
for (iov = (struct vki_iovec *)(Addr)ARG2;
|
|
iov < (struct vki_iovec *)(Addr)ARG2 + ARG3; iov++)
|
|
{
|
|
if (ML_(safe_to_deref) (iov, sizeof(struct vki_iovec))) {
|
|
if ((fdfl & VKI_O_ACCMODE) == VKI_O_RDONLY)
|
|
PRE_MEM_WRITE( "vmsplice(iov[...])",
|
|
(Addr)iov->iov_base, iov->iov_len );
|
|
else
|
|
PRE_MEM_READ( "vmsplice(iov[...])",
|
|
(Addr)iov->iov_base, iov->iov_len );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
POST(sys_vmsplice)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (RES > 0) {
|
|
Int fdfl = VG_(fcntl)(ARG1, VKI_F_GETFL, 0);
|
|
vg_assert(fdfl >= 0);
|
|
if ((fdfl & VKI_O_ACCMODE) == VKI_O_RDONLY)
|
|
{
|
|
const struct vki_iovec *iov;
|
|
for (iov = (struct vki_iovec *)(Addr)ARG2;
|
|
iov < (struct vki_iovec *)(Addr)ARG2 + ARG3; iov++)
|
|
{
|
|
POST_MEM_WRITE( (Addr)iov->iov_base, iov->iov_len );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
oprofile-related wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
#if defined(VGP_x86_linux)
|
|
PRE(sys_lookup_dcookie)
|
|
{
|
|
PRINT("sys_lookup_dcookie (0x%llx, %#lx, %lu)",
|
|
MERGE64(ARG1,ARG2), ARG3, ARG4);
|
|
PRE_REG_READ4(long, "lookup_dcookie",
|
|
vki_u32, MERGE64_FIRST(cookie), vki_u32, MERGE64_SECOND(cookie),
|
|
char *, buf, vki_size_t, len);
|
|
PRE_MEM_WRITE( "lookup_dcookie(buf)", ARG3, ARG4);
|
|
}
|
|
POST(sys_lookup_dcookie)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (ARG3 != (Addr)NULL)
|
|
POST_MEM_WRITE( ARG3, RES);
|
|
}
|
|
#endif
|
|
|
|
#if defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \
|
|
|| defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
|
|
PRE(sys_lookup_dcookie)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
PRINT("sys_lookup_dcookie ( %lu, %#lx, %lu )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(int, "lookup_dcookie",
|
|
unsigned long long, cookie, char *, buf, vki_size_t, len);
|
|
|
|
PRE_MEM_WRITE( "sys_lookup_dcookie(buf)", ARG2, ARG3 );
|
|
}
|
|
|
|
POST(sys_lookup_dcookie)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (ARG2 != (Addr)NULL)
|
|
POST_MEM_WRITE( ARG2, RES );
|
|
}
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------
|
|
fcntl wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
PRE(sys_fcntl)
|
|
{
|
|
switch (ARG2) {
|
|
// These ones ignore ARG3.
|
|
case VKI_F_GETFD:
|
|
case VKI_F_GETFL:
|
|
case VKI_F_GETOWN:
|
|
case VKI_F_GETSIG:
|
|
case VKI_F_GETLEASE:
|
|
case VKI_F_GETPIPE_SZ:
|
|
case VKI_F_GET_SEALS:
|
|
PRINT("sys_fcntl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
|
|
break;
|
|
|
|
// These ones use ARG3 as "arg".
|
|
case VKI_F_DUPFD:
|
|
case VKI_F_DUPFD_CLOEXEC:
|
|
case VKI_F_SETFD:
|
|
case VKI_F_SETFL:
|
|
case VKI_F_SETLEASE:
|
|
case VKI_F_NOTIFY:
|
|
case VKI_F_SETOWN:
|
|
case VKI_F_SETSIG:
|
|
case VKI_F_SETPIPE_SZ:
|
|
case VKI_F_ADD_SEALS:
|
|
PRINT("sys_fcntl[ARG3=='arg'] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd, unsigned long, arg);
|
|
break;
|
|
|
|
// These ones use ARG3 as "lock".
|
|
case VKI_F_GETLK:
|
|
case VKI_F_SETLK:
|
|
case VKI_F_SETLKW:
|
|
case VKI_F_OFD_GETLK:
|
|
case VKI_F_OFD_SETLK:
|
|
case VKI_F_OFD_SETLKW:
|
|
PRINT("sys_fcntl[ARG3=='lock'] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct vki_flock *, lock);
|
|
{
|
|
struct vki_flock *lock = (struct vki_flock *) (Addr)ARG3;
|
|
PRE_FIELD_READ("fcntl(lock->l_type)", lock->l_type);
|
|
PRE_FIELD_READ("fcntl(lock->l_whence)", lock->l_whence);
|
|
PRE_FIELD_READ("fcntl(lock->l_start)", lock->l_start);
|
|
PRE_FIELD_READ("fcntl(lock->l_len)", lock->l_len);
|
|
if (ARG2 == VKI_F_GETLK || ARG2 == VKI_F_OFD_GETLK) {
|
|
PRE_FIELD_WRITE("fcntl(lock->l_pid)", lock->l_pid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
# if defined(VGP_x86_linux) || defined(VGP_mips64_linux)
|
|
case VKI_F_GETLK64:
|
|
case VKI_F_SETLK64:
|
|
case VKI_F_SETLKW64:
|
|
PRINT("sys_fcntl[ARG3=='lock'] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct flock64 *, lock);
|
|
{
|
|
struct vki_flock64 *lock = (struct vki_flock64 *) (Addr)ARG3;
|
|
PRE_FIELD_READ("fcntl(lock->l_type)", lock->l_type);
|
|
PRE_FIELD_READ("fcntl(lock->l_whence)", lock->l_whence);
|
|
PRE_FIELD_READ("fcntl(lock->l_start)", lock->l_start);
|
|
PRE_FIELD_READ("fcntl(lock->l_len)", lock->l_len);
|
|
if (ARG2 == VKI_F_GETLK64) {
|
|
PRE_FIELD_WRITE("fcntl(lock->l_pid)", lock->l_pid);
|
|
}
|
|
}
|
|
break;
|
|
# endif
|
|
|
|
case VKI_F_SETOWN_EX:
|
|
PRINT("sys_fcntl[F_SETOWN_EX] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct vki_f_owner_ex *, arg);
|
|
PRE_MEM_READ("fcntl(F_SETOWN_EX)", ARG3, sizeof(struct vki_f_owner_ex));
|
|
break;
|
|
|
|
case VKI_F_GETOWN_EX:
|
|
PRINT("sys_fcntl[F_GETOWN_EX] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct vki_f_owner_ex *, arg);
|
|
PRE_MEM_WRITE("fcntl(F_GETOWN_EX)", ARG3, sizeof(struct vki_f_owner_ex));
|
|
break;
|
|
|
|
default:
|
|
PRINT("sys_fcntl[UNKNOWN] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
VG_(umsg)("Warning: unimplemented fcntl command: %" FMT_REGWORD "u\n",
|
|
ARG2);
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
break;
|
|
}
|
|
|
|
# if defined(VGP_x86_linux)
|
|
if (ARG2 == VKI_F_SETLKW || ARG2 == VKI_F_SETLKW64)
|
|
# else
|
|
if (ARG2 == VKI_F_SETLKW)
|
|
# endif
|
|
*flags |= SfMayBlock;
|
|
}
|
|
|
|
POST(sys_fcntl)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (ARG2 == VKI_F_DUPFD) {
|
|
if (!ML_(fd_allowed)(RES, "fcntl(DUPFD)", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_named)(tid, RES);
|
|
}
|
|
}
|
|
else if (ARG2 == VKI_F_DUPFD_CLOEXEC) {
|
|
if (!ML_(fd_allowed)(RES, "fcntl(DUPFD_CLOEXEC)", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_named)(tid, RES);
|
|
}
|
|
} else if (ARG2 == VKI_F_GETOWN_EX) {
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_f_owner_ex));
|
|
} else if (ARG2 == VKI_F_GETLK || ARG2 == VKI_F_OFD_GETLK) {
|
|
struct vki_flock *lock = (struct vki_flock *) (Addr)ARG3;
|
|
POST_FIELD_WRITE(lock->l_pid);
|
|
# if defined(VGP_x86_linux) || defined(VGP_mips64_linux)
|
|
} else if (ARG2 == VKI_F_GETLK64) {
|
|
struct vki_flock64 *lock = (struct vki_flock64 *) (Addr)ARG3;
|
|
PRE_FIELD_WRITE("fcntl(lock->l_pid)", lock->l_pid);
|
|
# endif
|
|
}
|
|
}
|
|
|
|
// XXX: wrapper only suitable for 32-bit systems
|
|
PRE(sys_fcntl64)
|
|
{
|
|
switch (ARG2) {
|
|
// These ones ignore ARG3.
|
|
case VKI_F_GETFD:
|
|
case VKI_F_GETFL:
|
|
case VKI_F_GETOWN:
|
|
case VKI_F_SETOWN:
|
|
case VKI_F_GETSIG:
|
|
case VKI_F_SETSIG:
|
|
case VKI_F_GETLEASE:
|
|
case VKI_F_GET_SEALS:
|
|
PRINT("sys_fcntl64 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "fcntl64", unsigned int, fd, unsigned int, cmd);
|
|
break;
|
|
|
|
// These ones use ARG3 as "arg".
|
|
case VKI_F_DUPFD:
|
|
case VKI_F_DUPFD_CLOEXEC:
|
|
case VKI_F_SETFD:
|
|
case VKI_F_SETFL:
|
|
case VKI_F_SETLEASE:
|
|
case VKI_F_NOTIFY:
|
|
case VKI_F_ADD_SEALS:
|
|
PRINT("sys_fcntl64[ARG3=='arg'] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl64",
|
|
unsigned int, fd, unsigned int, cmd, unsigned long, arg);
|
|
break;
|
|
|
|
// These ones use ARG3 as "lock".
|
|
case VKI_F_GETLK:
|
|
case VKI_F_SETLK:
|
|
case VKI_F_SETLKW:
|
|
# if defined(VGP_x86_linux)
|
|
case VKI_F_GETLK64:
|
|
case VKI_F_SETLK64:
|
|
case VKI_F_SETLKW64:
|
|
# endif
|
|
case VKI_F_OFD_GETLK:
|
|
case VKI_F_OFD_SETLK:
|
|
case VKI_F_OFD_SETLKW:
|
|
PRINT("sys_fcntl64[ARG3=='lock'] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl64",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct flock64 *, lock);
|
|
break;
|
|
|
|
case VKI_F_SETOWN_EX:
|
|
PRINT("sys_fcntl[F_SETOWN_EX] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct vki_f_owner_ex *, arg);
|
|
PRE_MEM_READ("fcntl(F_SETOWN_EX)", ARG3, sizeof(struct vki_f_owner_ex));
|
|
break;
|
|
|
|
case VKI_F_GETOWN_EX:
|
|
PRINT("sys_fcntl[F_GETOWN_EX] ( %" FMT_REGWORD "u, %" FMT_REGWORD
|
|
"u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "fcntl",
|
|
unsigned int, fd, unsigned int, cmd,
|
|
struct vki_f_owner_ex *, arg);
|
|
PRE_MEM_WRITE("fcntl(F_GETOWN_EX)", ARG3, sizeof(struct vki_f_owner_ex));
|
|
break;
|
|
}
|
|
|
|
# if defined(VGP_x86_linux)
|
|
if (ARG2 == VKI_F_SETLKW || ARG2 == VKI_F_SETLKW64)
|
|
# else
|
|
if (ARG2 == VKI_F_SETLKW)
|
|
# endif
|
|
*flags |= SfMayBlock;
|
|
}
|
|
|
|
POST(sys_fcntl64)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (ARG2 == VKI_F_DUPFD) {
|
|
if (!ML_(fd_allowed)(RES, "fcntl64(DUPFD)", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_named)(tid, RES);
|
|
}
|
|
}
|
|
else if (ARG2 == VKI_F_DUPFD_CLOEXEC) {
|
|
if (!ML_(fd_allowed)(RES, "fcntl64(DUPFD_CLOEXEC)", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_named)(tid, RES);
|
|
}
|
|
} else if (ARG2 == VKI_F_GETOWN_EX) {
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_f_owner_ex));
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
ioctl wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
struct vg_drm_version_info {
|
|
struct vki_drm_version data;
|
|
struct vki_drm_version *orig; // Original ARG3 pointer value at syscall entry.
|
|
};
|
|
|
|
PRE(sys_ioctl)
|
|
{
|
|
*flags |= SfMayBlock;
|
|
|
|
ARG2 = (UInt)ARG2;
|
|
|
|
// We first handle the ones that don't use ARG3 (even as a
|
|
// scalar/non-pointer argument).
|
|
switch (ARG2 /* request */) {
|
|
|
|
/* asm-generic/ioctls.h */
|
|
case VKI_FIOCLEX:
|
|
case VKI_FIONCLEX:
|
|
case VKI_TIOCNOTTY:
|
|
|
|
/* linux perf_event ioctls */
|
|
case VKI_PERF_EVENT_IOC_ENABLE:
|
|
case VKI_PERF_EVENT_IOC_DISABLE:
|
|
|
|
/* linux/soundcard interface (ALSA) */
|
|
case VKI_SNDRV_PCM_IOCTL_HW_FREE:
|
|
case VKI_SNDRV_PCM_IOCTL_HWSYNC:
|
|
case VKI_SNDRV_PCM_IOCTL_PREPARE:
|
|
case VKI_SNDRV_PCM_IOCTL_RESET:
|
|
case VKI_SNDRV_PCM_IOCTL_START:
|
|
case VKI_SNDRV_PCM_IOCTL_DROP:
|
|
case VKI_SNDRV_PCM_IOCTL_DRAIN:
|
|
case VKI_SNDRV_PCM_IOCTL_RESUME:
|
|
case VKI_SNDRV_PCM_IOCTL_XRUN:
|
|
case VKI_SNDRV_PCM_IOCTL_UNLINK:
|
|
case VKI_SNDRV_TIMER_IOCTL_START:
|
|
case VKI_SNDRV_TIMER_IOCTL_STOP:
|
|
case VKI_SNDRV_TIMER_IOCTL_CONTINUE:
|
|
case VKI_SNDRV_TIMER_IOCTL_PAUSE:
|
|
|
|
/* SCSI no operand */
|
|
case VKI_SCSI_IOCTL_DOORLOCK:
|
|
case VKI_SCSI_IOCTL_DOORUNLOCK:
|
|
|
|
/* CDROM stuff. */
|
|
case VKI_CDROM_DISC_STATUS:
|
|
case VKI_CDROMSTOP:
|
|
|
|
/* DVD stuff */
|
|
case VKI_DVD_READ_STRUCT:
|
|
|
|
/* KVM ioctls that don't check for a numeric value as parameter */
|
|
case VKI_KVM_S390_ENABLE_SIE:
|
|
case VKI_KVM_CREATE_IRQCHIP:
|
|
case VKI_KVM_S390_INITIAL_RESET:
|
|
case VKI_KVM_KVMCLOCK_CTRL:
|
|
|
|
/* vhost without parameter */
|
|
case VKI_VHOST_SET_OWNER:
|
|
case VKI_VHOST_RESET_OWNER:
|
|
|
|
/* User input device creation */
|
|
case VKI_UI_DEV_CREATE:
|
|
case VKI_UI_DEV_DESTROY:
|
|
|
|
/* InfiniBand */
|
|
case VKI_IB_USER_MAD_ENABLE_PKEY:
|
|
|
|
/* Lustre */
|
|
case VKI_LL_IOC_GROUP_LOCK:
|
|
case VKI_LL_IOC_GROUP_UNLOCK:
|
|
|
|
/* V4L2 */
|
|
case VKI_V4L2_LOG_STATUS:
|
|
|
|
/* Mesa */
|
|
case VKI_DRM_IOCTL_I915_GEM_THROTTLE:
|
|
|
|
/* DVB */
|
|
case VKI_DMX_STOP:
|
|
PRINT("sys_ioctl ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x )", ARG1, ARG2);
|
|
PRE_REG_READ2(long, "ioctl",
|
|
unsigned int, fd, unsigned int, request);
|
|
return;
|
|
|
|
default:
|
|
PRINT("sys_ioctl ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, 0x%"
|
|
FMT_REGWORD "x )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "ioctl",
|
|
unsigned int, fd, unsigned int, request, unsigned long, arg);
|
|
break;
|
|
}
|
|
|
|
// We now handle those that do look at ARG3 (and unknown ones fall into
|
|
// this category). Nb: some of these may well belong in the
|
|
// doesn't-use-ARG3 switch above.
|
|
switch (ARG2 /* request */) {
|
|
|
|
case VKI_ION_IOC_ALLOC: {
|
|
struct vki_ion_allocation_data* data
|
|
= (struct vki_ion_allocation_data*)(Addr)ARG3;
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_ALLOC).len", data->len);
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_ALLOC).align", data->align);
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_ALLOC).heap_id_mask", data->heap_id_mask);
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_ALLOC).flags", data->flags);
|
|
PRE_FIELD_WRITE("ioctl(ION_IOC_ALLOC).handle", data->handle);
|
|
break;
|
|
}
|
|
case VKI_ION_IOC_MAP: {
|
|
struct vki_ion_fd_data* data = (struct vki_ion_fd_data*)(Addr)ARG3;
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_MAP).handle", data->handle);
|
|
PRE_FIELD_WRITE("ioctl(ION_IOC_MAP).fd", data->fd);
|
|
break;
|
|
}
|
|
case VKI_ION_IOC_IMPORT: {
|
|
struct vki_ion_fd_data* data = (struct vki_ion_fd_data*)(Addr)ARG3;
|
|
PRE_FIELD_READ ("ioctl(ION_IOC_IMPORT).fd", data->fd);
|
|
PRE_FIELD_WRITE("ioctl(ION_IOC_IMPORT).handle", data->handle);
|
|
break;
|
|
}
|
|
|
|
case VKI_SYNC_IOC_MERGE: {
|
|
struct vki_sync_merge_data* data =
|
|
(struct vki_sync_merge_data*)(Addr)ARG3;
|
|
PRE_FIELD_READ ("ioctl(SYNC_IOC_MERGE).fd2", data->fd2);
|
|
PRE_MEM_RASCIIZ("ioctl(SYNC_IOC_MERGE).name", (Addr)(&data->name[0]));
|
|
PRE_FIELD_WRITE("ioctl(SYNC_IOC_MERGE).fence", data->fence);
|
|
break;
|
|
}
|
|
|
|
case VKI_TCSETS:
|
|
case VKI_TCSETSW:
|
|
case VKI_TCSETSF:
|
|
PRE_MEM_READ( "ioctl(TCSET{S,SW,SF})", ARG3, sizeof(struct vki_termios) );
|
|
break;
|
|
case VKI_TCGETS:
|
|
PRE_MEM_WRITE( "ioctl(TCGETS)", ARG3, sizeof(struct vki_termios) );
|
|
break;
|
|
case VKI_TCSETA:
|
|
case VKI_TCSETAW:
|
|
case VKI_TCSETAF:
|
|
PRE_MEM_READ( "ioctl(TCSET{A,AW,AF})", ARG3, sizeof(struct vki_termio) );
|
|
break;
|
|
case VKI_TCGETA:
|
|
PRE_MEM_WRITE( "ioctl(TCGETA)", ARG3, sizeof(struct vki_termio) );
|
|
break;
|
|
case VKI_TCSBRK:
|
|
case VKI_TCXONC:
|
|
case VKI_TCSBRKP:
|
|
case VKI_TCFLSH:
|
|
case VKI_TIOCSIG:
|
|
/* These just take an int by value */
|
|
break;
|
|
case VKI_TIOCGWINSZ:
|
|
PRE_MEM_WRITE( "ioctl(TIOCGWINSZ)", ARG3, sizeof(struct vki_winsize) );
|
|
break;
|
|
case VKI_TIOCSWINSZ:
|
|
PRE_MEM_READ( "ioctl(TIOCSWINSZ)", ARG3, sizeof(struct vki_winsize) );
|
|
break;
|
|
case VKI_TIOCMBIS:
|
|
PRE_MEM_READ( "ioctl(TIOCMBIS)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TIOCMBIC:
|
|
PRE_MEM_READ( "ioctl(TIOCMBIC)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TIOCMSET:
|
|
PRE_MEM_READ( "ioctl(TIOCMSET)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TIOCMGET:
|
|
PRE_MEM_WRITE( "ioctl(TIOCMGET)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TIOCLINUX:
|
|
PRE_MEM_READ( "ioctl(TIOCLINUX)", ARG3, sizeof(char *) );
|
|
if (*(char *)(Addr)ARG3 == 11) {
|
|
PRE_MEM_READ( "ioctl(TIOCLINUX, 11)", ARG3, 2 * sizeof(char *) );
|
|
}
|
|
break;
|
|
case VKI_TIOCGPGRP:
|
|
/* Get process group ID for foreground processing group. */
|
|
PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
|
|
break;
|
|
case VKI_TIOCSPGRP:
|
|
/* Set a process group ID? */
|
|
PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
|
|
break;
|
|
case VKI_TIOCGPTN: /* Get Pty Number (of pty-mux device) */
|
|
PRE_MEM_WRITE( "ioctl(TIOCGPTN)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TIOCSCTTY:
|
|
/* Just takes an int value. */
|
|
break;
|
|
case VKI_TIOCSPTLCK: /* Lock/unlock Pty */
|
|
PRE_MEM_READ( "ioctl(TIOCSPTLCK)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_FIONBIO:
|
|
PRE_MEM_READ( "ioctl(FIONBIO)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_FIOASYNC:
|
|
PRE_MEM_READ( "ioctl(FIOASYNC)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_FIONREAD: /* identical to SIOCINQ */
|
|
PRE_MEM_WRITE( "ioctl(FIONREAD)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_FIOQSIZE:
|
|
PRE_MEM_WRITE( "ioctl(FIOQSIZE)", ARG3, sizeof(vki_loff_t) );
|
|
break;
|
|
|
|
case VKI_TIOCSERGETLSR:
|
|
PRE_MEM_WRITE( "ioctl(TIOCSERGETLSR)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TIOCGICOUNT:
|
|
PRE_MEM_WRITE( "ioctl(TIOCGICOUNT)", ARG3,
|
|
sizeof(struct vki_serial_icounter_struct) );
|
|
break;
|
|
|
|
case VKI_SG_SET_COMMAND_Q:
|
|
PRE_MEM_READ( "ioctl(SG_SET_COMMAND_Q)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_IO:
|
|
PRE_MEM_READ( "ioctl(SG_IO)", ARG3, sizeof(vki_sg_io_hdr_t) );
|
|
{
|
|
vki_sg_io_hdr_t *sgio = (vki_sg_io_hdr_t*)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(SG_IO)", (Addr)sgio->cmdp, sgio->cmd_len );
|
|
if ( sgio->dxfer_direction == VKI_SG_DXFER_TO_DEV ||
|
|
sgio->dxfer_direction == VKI_SG_DXFER_TO_FROM_DEV ) {
|
|
PRE_MEM_READ( "ioctl(SG_IO)", (Addr)sgio->dxferp, sgio->dxfer_len );
|
|
}
|
|
}
|
|
break;
|
|
case VKI_SG_GET_SCSI_ID:
|
|
PRE_MEM_WRITE( "ioctl(SG_GET_SCSI_ID)", ARG3, sizeof(vki_sg_scsi_id_t) );
|
|
break;
|
|
case VKI_SG_SET_RESERVED_SIZE:
|
|
PRE_MEM_READ( "ioctl(SG_SET_RESERVED_SIZE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_SET_TIMEOUT:
|
|
PRE_MEM_READ( "ioctl(SG_SET_TIMEOUT)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_GET_RESERVED_SIZE:
|
|
PRE_MEM_WRITE( "ioctl(SG_GET_RESERVED_SIZE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_GET_TIMEOUT:
|
|
break;
|
|
case VKI_SG_GET_VERSION_NUM:
|
|
PRE_MEM_WRITE( "ioctl(SG_GET_VERSION_NUM)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_EMULATED_HOST: /* 0x2203 */
|
|
PRE_MEM_WRITE( "ioctl(SG_EMULATED_HOST)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SG_GET_SG_TABLESIZE: /* 0x227f */
|
|
PRE_MEM_WRITE( "ioctl(SG_GET_SG_TABLESIZE)", ARG3, sizeof(int) );
|
|
break;
|
|
|
|
case VKI_IIOCGETCPS:
|
|
PRE_MEM_WRITE( "ioctl(IIOCGETCPS)", ARG3,
|
|
VKI_ISDN_MAX_CHANNELS * 2 * sizeof(unsigned long) );
|
|
break;
|
|
case VKI_IIOCNETGPN:
|
|
PRE_MEM_READ( "ioctl(IIOCNETGPN)",
|
|
(Addr)&((vki_isdn_net_ioctl_phone *)(Addr)ARG3)->name,
|
|
sizeof(((vki_isdn_net_ioctl_phone *)(Addr)ARG3)->name) );
|
|
PRE_MEM_WRITE( "ioctl(IIOCNETGPN)", ARG3,
|
|
sizeof(vki_isdn_net_ioctl_phone) );
|
|
break;
|
|
|
|
/* These all use struct ifreq AFAIK */
|
|
case VKI_SIOCGIFINDEX: /* get iface index */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFINDEX)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFINDEX)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFFLAGS: /* get flags */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFFLAGS)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFFLAGS)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFHWADDR: /* Get hardware address */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFHWADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFHWADDR)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFMTU: /* get MTU size */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMTU)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFMTU)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFADDR: /* get PA address */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFADDR)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFNETMASK: /* get network PA mask */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFNETMASK)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFNETMASK)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFMETRIC: /* get metric */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMETRIC)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFMETRIC)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFMAP: /* Get device parameters */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMAP)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFMAP)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFTXQLEN: /* Get the tx queue length */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFTXQLEN)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFTXQLEN)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFDSTADDR: /* get remote PA address */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFDSTADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFDSTADDR)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFBRDADDR: /* get broadcast PA address */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFBRDADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFBRDADDR)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFNAME: /* get iface name */
|
|
PRE_MEM_READ( "ioctl(SIOCGIFNAME)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_ifindex,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_ifindex));
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFNAME)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
|
|
case VKI_SIOCETHTOOL: { /* ethtool(8) interface */
|
|
struct vki_ifreq *ir = (struct vki_ifreq *)(Addr)ARG3;
|
|
// The kernel will have to look at ifr_data to determine which operation
|
|
// to perform.
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,ir->ifr_data)",
|
|
(Addr)ir->vki_ifr_data, sizeof(vki_u32) );
|
|
|
|
PRINT("SIOCETHTOOL( 0x%x )", *(vki_u32 *)ir->vki_ifr_data );
|
|
|
|
// Is this correct? Is ifr_name *always* looked at?
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCETHTOOL,ir->ifr_name)",
|
|
(Addr)ir->vki_ifr_name );
|
|
|
|
// At least for ETHTOOL_GSET, it is apparently incorrect to insist that
|
|
// the whole structure is defined. So in this case, just check it's
|
|
// accessible.
|
|
switch ( *(vki_u32 *)ir->vki_ifr_data ) {
|
|
case VKI_ETHTOOL_GSET:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,ir)",
|
|
(Addr)ir, sizeof(struct vki_ifreq) );
|
|
break;
|
|
default:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,ir)",
|
|
(Addr)ir, sizeof(struct vki_ifreq) );
|
|
break;
|
|
}
|
|
|
|
// Now perform the relevant pre-action for the operation.
|
|
switch ( *(vki_u32 *)ir->vki_ifr_data ) {
|
|
case VKI_ETHTOOL_GSET:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GSET)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_cmd) );
|
|
break;
|
|
case VKI_ETHTOOL_SSET:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SSET)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_cmd) );
|
|
break;
|
|
case VKI_ETHTOOL_GDRVINFO:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GDRVINFO)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_drvinfo) );
|
|
break;
|
|
case VKI_ETHTOOL_GREGS:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,GREGS)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_regs) );
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GREGS)",
|
|
(Addr)((struct vki_ethtool_regs *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_regs *)ir->vki_ifr_data)->len );
|
|
break;
|
|
case VKI_ETHTOOL_GWOL:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GWOL)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_wolinfo) );
|
|
break;
|
|
case VKI_ETHTOOL_SWOL:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SWOL)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_wolinfo) );
|
|
break;
|
|
case VKI_ETHTOOL_GMSGLVL:
|
|
case VKI_ETHTOOL_GLINK:
|
|
case VKI_ETHTOOL_GRXCSUM:
|
|
case VKI_ETHTOOL_GSG:
|
|
case VKI_ETHTOOL_GTSO:
|
|
case VKI_ETHTOOL_GUFO:
|
|
case VKI_ETHTOOL_GGSO:
|
|
case VKI_ETHTOOL_GFLAGS:
|
|
case VKI_ETHTOOL_GGRO:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,Gvalue)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_value) );
|
|
break;
|
|
case VKI_ETHTOOL_SMSGLVL:
|
|
case VKI_ETHTOOL_SRXCSUM:
|
|
case VKI_ETHTOOL_SSG:
|
|
case VKI_ETHTOOL_STSO:
|
|
case VKI_ETHTOOL_SUFO:
|
|
case VKI_ETHTOOL_SGSO:
|
|
case VKI_ETHTOOL_SFLAGS:
|
|
case VKI_ETHTOOL_SGRO:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,Svalue)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_value) );
|
|
break;
|
|
case VKI_ETHTOOL_NWAY_RST:
|
|
break;
|
|
case VKI_ETHTOOL_GRINGPARAM:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GRINGPARAM)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_ringparam) );
|
|
break;
|
|
case VKI_ETHTOOL_SRINGPARAM:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SRINGPARAM)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_ringparam) );
|
|
break;
|
|
case VKI_ETHTOOL_TEST:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,TEST)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_test) );
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,TEST)",
|
|
(Addr)((struct vki_ethtool_test *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_test *)ir->vki_ifr_data)->len * sizeof(__vki_u64) );
|
|
break;
|
|
case VKI_ETHTOOL_PHYS_ID:
|
|
break;
|
|
case VKI_ETHTOOL_GPERMADDR:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,GPERMADDR)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_perm_addr) );
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GPERMADDR)",
|
|
(Addr)((struct vki_ethtool_perm_addr *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_perm_addr *)ir->vki_ifr_data)->size );
|
|
break;
|
|
case VKI_ETHTOOL_RESET:
|
|
break;
|
|
case VKI_ETHTOOL_GSSET_INFO:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,GSSET_INFO)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_sset_info) );
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GSSET_INFO)",
|
|
(Addr)((struct vki_ethtool_sset_info *)ir->vki_ifr_data)->data,
|
|
__builtin_popcountll(((struct vki_ethtool_sset_info *)ir->vki_ifr_data)->sset_mask) * sizeof(__vki_u32) );
|
|
break;
|
|
case VKI_ETHTOOL_GFEATURES:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,GFEATURES)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_gfeatures) );
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GFEATURES)",
|
|
(Addr)((struct vki_ethtool_gfeatures *)ir->vki_ifr_data)->features,
|
|
((struct vki_ethtool_gfeatures *)ir->vki_ifr_data)->size * sizeof(struct vki_ethtool_get_features_block) );
|
|
break;
|
|
case VKI_ETHTOOL_SFEATURES:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SFEATURES)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_sfeatures) );
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SFEATURES)",
|
|
(Addr)((struct vki_ethtool_sfeatures *)ir->vki_ifr_data)->features,
|
|
((struct vki_ethtool_sfeatures *)ir->vki_ifr_data)->size * sizeof(struct vki_ethtool_set_features_block) );
|
|
break;
|
|
case VKI_ETHTOOL_GCHANNELS:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GCHANNELS)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_channels) );
|
|
break;
|
|
case VKI_ETHTOOL_SCHANNELS:
|
|
PRE_MEM_READ( "ioctl(SIOCETHTOOL,SCHANNELS)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_channels) );
|
|
break;
|
|
case VKI_ETHTOOL_GET_TS_INFO:
|
|
PRE_MEM_WRITE( "ioctl(SIOCETHTOOL,GET_TS_INFO)",
|
|
(Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_ts_info) );
|
|
break;
|
|
}
|
|
break;
|
|
} /* case VKI_SIOCETHTOOL */
|
|
|
|
case VKI_SIOCGMIIPHY: /* get hardware entry */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMIIPHY)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFMIIPHY)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGMIIREG: /* get hardware entry registers */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMIIREG)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCGIFMIIREG)",
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id));
|
|
PRE_MEM_READ( "ioctl(SIOCGIFMIIREG)",
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->reg_num,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->reg_num));
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFMIIREG)", ARG3,
|
|
sizeof(struct vki_ifreq));
|
|
break;
|
|
case VKI_SIOCGIFCONF: /* get iface list */
|
|
/* WAS:
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
|
|
KERNEL_DO_SYSCALL(tid,RES);
|
|
if (!VG_(is_kerror)(RES) && RES == 0)
|
|
POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
|
|
*/
|
|
PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
|
|
(Addr)&((struct vki_ifconf *)(Addr)ARG3)->ifc_len,
|
|
sizeof(((struct vki_ifconf *)(Addr)ARG3)->ifc_len));
|
|
PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
|
|
(Addr)&((struct vki_ifconf *)(Addr)ARG3)->vki_ifc_buf,
|
|
sizeof(((struct vki_ifconf *)(Addr)ARG3)->vki_ifc_buf));
|
|
if ( ARG3 ) {
|
|
// TODO len must be readable and writable
|
|
// buf pointer only needs to be readable
|
|
struct vki_ifconf *ifc = (struct vki_ifconf *) (Addr)ARG3;
|
|
PRE_MEM_WRITE( "ioctl(SIOCGIFCONF).ifc_buf",
|
|
(Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
|
|
}
|
|
break;
|
|
case VKI_SIOCGSTAMP:
|
|
PRE_MEM_WRITE( "ioctl(SIOCGSTAMP)", ARG3, sizeof(struct vki_timeval));
|
|
break;
|
|
case VKI_SIOCGSTAMPNS:
|
|
PRE_MEM_WRITE( "ioctl(SIOCGSTAMPNS)", ARG3, sizeof(struct vki_timespec));
|
|
break;
|
|
/* SIOCOUTQ is an ioctl that, when called on a socket, returns
|
|
the number of bytes currently in that socket's send buffer.
|
|
It writes this value as an int to the memory location
|
|
indicated by the third argument of ioctl(2). */
|
|
case VKI_SIOCOUTQ:
|
|
PRE_MEM_WRITE( "ioctl(SIOCOUTQ)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SIOCGRARP: /* get RARP table entry */
|
|
case VKI_SIOCGARP: /* get ARP table entry */
|
|
PRE_MEM_WRITE( "ioctl(SIOCGARP)", ARG3, sizeof(struct vki_arpreq));
|
|
break;
|
|
|
|
case VKI_SIOCSIFFLAGS: /* set flags */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFFLAGS)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFFLAGS)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags) );
|
|
break;
|
|
case VKI_SIOCSIFMAP: /* Set device parameters */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMAP)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFMAP)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_map,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_map) );
|
|
break;
|
|
case VKI_SIOCSHWTSTAMP: /* Set hardware time stamping */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSHWTSTAMP)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSHWTSTAMP)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data,
|
|
sizeof(struct vki_hwtstamp_config) );
|
|
break;
|
|
case VKI_SIOCSIFTXQLEN: /* Set the tx queue length */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFTXQLEN)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFTXQLEN)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_qlen,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_qlen) );
|
|
break;
|
|
case VKI_SIOCSIFADDR: /* set PA address */
|
|
case VKI_SIOCSIFDSTADDR: /* set remote PA address */
|
|
case VKI_SIOCSIFBRDADDR: /* set broadcast PA address */
|
|
case VKI_SIOCSIFNETMASK: /* set network PA mask */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIF*ADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIF*ADDR)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_addr,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_addr) );
|
|
break;
|
|
case VKI_SIOCSIFMETRIC: /* set metric */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMETRIC)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFMETRIC)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_metric,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_metric) );
|
|
break;
|
|
case VKI_SIOCSIFMTU: /* set MTU size */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMTU)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFMTU)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_mtu,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_mtu) );
|
|
break;
|
|
case VKI_SIOCSIFHWADDR: /* set hardware address */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSIFHWADDR)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSIFHWADDR)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_hwaddr,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_hwaddr) );
|
|
break;
|
|
case VKI_SIOCSMIIREG: /* set hardware entry registers */
|
|
PRE_MEM_RASCIIZ( "ioctl(SIOCSMIIREG)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(SIOCSMIIREG)",
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id));
|
|
PRE_MEM_READ( "ioctl(SIOCSMIIREG)",
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->reg_num,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->reg_num));
|
|
PRE_MEM_READ( "ioctl(SIOCSMIIREG)",
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->val_in,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->val_in));
|
|
break;
|
|
/* Routing table calls. */
|
|
case VKI_SIOCADDRT: /* add routing table entry */
|
|
case VKI_SIOCDELRT: /* delete routing table entry */
|
|
PRE_MEM_READ( "ioctl(SIOCADDRT/DELRT)", ARG3,
|
|
sizeof(struct vki_rtentry));
|
|
break;
|
|
|
|
/* tun/tap related ioctls */
|
|
case VKI_TUNSETNOCSUM:
|
|
case VKI_TUNSETDEBUG:
|
|
break;
|
|
case VKI_TUNSETIFF:
|
|
PRE_MEM_RASCIIZ( "ioctl(TUNSETIFF)",
|
|
(Addr)((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name );
|
|
PRE_MEM_READ( "ioctl(TUNSETIFF)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags) );
|
|
PRE_MEM_WRITE( "ioctl(TUNSETIFF)", ARG3, sizeof(struct vki_ifreq) );
|
|
break;
|
|
case VKI_TUNSETPERSIST:
|
|
case VKI_TUNSETOWNER:
|
|
case VKI_TUNSETLINK:
|
|
case VKI_TUNSETGROUP:
|
|
break;
|
|
case VKI_TUNGETFEATURES:
|
|
PRE_MEM_WRITE( "ioctl(TUNGETFEATURES)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TUNSETOFFLOAD:
|
|
break;
|
|
case VKI_TUNGETIFF:
|
|
PRE_MEM_WRITE( "ioctl(TUNGETIFF)", ARG3, sizeof(struct vki_ifreq) );
|
|
break;
|
|
case VKI_TUNGETSNDBUF:
|
|
PRE_MEM_WRITE( "ioctl(TUNGETSNDBUF)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TUNSETSNDBUF:
|
|
PRE_MEM_READ( "ioctl(TUNSETSNDBUF)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TUNGETVNETHDRSZ:
|
|
PRE_MEM_WRITE( "ioctl(TUNGETVNETHDRSZ)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TUNSETVNETHDRSZ:
|
|
PRE_MEM_READ( "ioctl(TUNSETVNETHDRSZ)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TUNSETQUEUE:
|
|
PRE_MEM_READ( "ioctl(TUNSETQUEUE)",
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags) );
|
|
break;
|
|
case VKI_TUNSETIFINDEX:
|
|
PRE_MEM_READ( "ioctl(TUNSETIFINDEX)", ARG3, sizeof(unsigned int));
|
|
break;
|
|
|
|
/* RARP cache control calls. */
|
|
case VKI_SIOCDRARP: /* delete RARP table entry */
|
|
case VKI_SIOCSRARP: /* set RARP table entry */
|
|
/* ARP cache control calls. */
|
|
case VKI_SIOCSARP: /* set ARP table entry */
|
|
case VKI_SIOCDARP: /* delete ARP table entry */
|
|
PRE_MEM_READ( "ioctl(SIOCSIFFLAGS)", ARG3, sizeof(struct vki_ifreq));
|
|
break;
|
|
|
|
case VKI_SIOCGPGRP:
|
|
PRE_MEM_WRITE( "ioctl(SIOCGPGRP)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SIOCSPGRP:
|
|
PRE_MEM_READ( "ioctl(SIOCSPGRP)", ARG3, sizeof(int) );
|
|
//tst->sys_flags &= ~SfMayBlock;
|
|
break;
|
|
|
|
case VKI_SIOCATMARK:
|
|
PRE_MEM_READ( "ioctl(SIOCATMARK)", ARG3, sizeof(int) );
|
|
break;
|
|
|
|
/* linux/soundcard interface (OSS) */
|
|
case VKI_SNDCTL_SEQ_GETOUTCOUNT:
|
|
case VKI_SNDCTL_SEQ_GETINCOUNT:
|
|
case VKI_SNDCTL_SEQ_PERCMODE:
|
|
case VKI_SNDCTL_SEQ_TESTMIDI:
|
|
case VKI_SNDCTL_SEQ_RESETSAMPLES:
|
|
case VKI_SNDCTL_SEQ_NRSYNTHS:
|
|
case VKI_SNDCTL_SEQ_NRMIDIS:
|
|
case VKI_SNDCTL_SEQ_GETTIME:
|
|
case VKI_SNDCTL_DSP_GETBLKSIZE:
|
|
case VKI_SNDCTL_DSP_GETFMTS:
|
|
case VKI_SNDCTL_DSP_GETTRIGGER:
|
|
case VKI_SNDCTL_DSP_GETODELAY:
|
|
case VKI_SNDCTL_DSP_GETSPDIF:
|
|
case VKI_SNDCTL_DSP_GETCAPS:
|
|
case VKI_SOUND_PCM_READ_RATE:
|
|
case VKI_SOUND_PCM_READ_CHANNELS:
|
|
case VKI_SOUND_PCM_READ_BITS:
|
|
case VKI_SOUND_PCM_READ_FILTER:
|
|
PRE_MEM_WRITE( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOR, int))",
|
|
ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SNDCTL_SEQ_CTRLRATE:
|
|
case VKI_SNDCTL_DSP_SPEED:
|
|
case VKI_SNDCTL_DSP_STEREO:
|
|
case VKI_SNDCTL_DSP_CHANNELS:
|
|
case VKI_SOUND_PCM_WRITE_FILTER:
|
|
case VKI_SNDCTL_DSP_SUBDIVIDE:
|
|
case VKI_SNDCTL_DSP_SETFRAGMENT:
|
|
case VKI_SNDCTL_DSP_SETFMT:
|
|
case VKI_SNDCTL_DSP_GETCHANNELMASK:
|
|
case VKI_SNDCTL_DSP_BIND_CHANNEL:
|
|
case VKI_SNDCTL_TMR_TIMEBASE:
|
|
case VKI_SNDCTL_TMR_TEMPO:
|
|
case VKI_SNDCTL_TMR_SOURCE:
|
|
case VKI_SNDCTL_MIDI_PRETIME:
|
|
case VKI_SNDCTL_MIDI_MPUMODE:
|
|
PRE_MEM_READ( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOWR, int))",
|
|
ARG3, sizeof(int));
|
|
PRE_MEM_WRITE( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOWR, int))",
|
|
ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SNDCTL_DSP_GETOSPACE:
|
|
case VKI_SNDCTL_DSP_GETISPACE:
|
|
PRE_MEM_WRITE( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOR, audio_buf_info))",
|
|
ARG3, sizeof(vki_audio_buf_info));
|
|
break;
|
|
case VKI_SNDCTL_DSP_NONBLOCK:
|
|
break;
|
|
case VKI_SNDCTL_DSP_SETTRIGGER:
|
|
PRE_MEM_READ( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOW, int))",
|
|
ARG3, sizeof(int));
|
|
break;
|
|
|
|
case VKI_SNDCTL_DSP_POST:
|
|
case VKI_SNDCTL_DSP_RESET:
|
|
case VKI_SNDCTL_DSP_SYNC:
|
|
case VKI_SNDCTL_DSP_SETSYNCRO:
|
|
case VKI_SNDCTL_DSP_SETDUPLEX:
|
|
break;
|
|
|
|
/* linux/soundcard interface (ALSA) */
|
|
case VKI_SNDRV_PCM_IOCTL_PAUSE:
|
|
case VKI_SNDRV_PCM_IOCTL_LINK:
|
|
/* these just take an int by value */
|
|
break;
|
|
case VKI_SNDRV_CTL_IOCTL_PVERSION:
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_PVERSION)", (Addr)ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_SNDRV_CTL_IOCTL_CARD_INFO:
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_CARD_INFO)", (Addr)ARG3, sizeof(struct vki_snd_ctl_card_info) );
|
|
break;
|
|
case VKI_SNDRV_CTL_IOCTL_ELEM_LIST: {
|
|
struct vki_snd_ctl_elem_list *data =
|
|
(struct vki_snd_ctl_elem_list *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->offset, sizeof(data->offset) );
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->space, sizeof(data->space) );
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->used, sizeof(data->used) );
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->count, sizeof(data->count) );
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->pids, sizeof(data->pids) );
|
|
if (data->pids) {
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)data->pids, sizeof(struct vki_snd_ctl_elem_id) * data->space );
|
|
}
|
|
break;
|
|
}
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_READ: {
|
|
struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)&data->numid, sizeof(data->numid) );
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)&data->length, sizeof(data->length) );
|
|
PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)data->tlv, data->length );
|
|
break;
|
|
}
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_WRITE:
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_COMMAND: {
|
|
struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)&data->numid, sizeof(data->numid) );
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)&data->length, sizeof(data->length) );
|
|
PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)data->tlv, data->length );
|
|
break;
|
|
}
|
|
|
|
/* Real Time Clock (/dev/rtc) ioctls */
|
|
case VKI_RTC_UIE_ON:
|
|
case VKI_RTC_UIE_OFF:
|
|
case VKI_RTC_AIE_ON:
|
|
case VKI_RTC_AIE_OFF:
|
|
case VKI_RTC_PIE_ON:
|
|
case VKI_RTC_PIE_OFF:
|
|
case VKI_RTC_IRQP_SET:
|
|
break;
|
|
case VKI_RTC_RD_TIME:
|
|
case VKI_RTC_ALM_READ:
|
|
PRE_MEM_WRITE( "ioctl(RTC_RD_TIME/ALM_READ)",
|
|
ARG3, sizeof(struct vki_rtc_time));
|
|
break;
|
|
case VKI_RTC_ALM_SET:
|
|
PRE_MEM_READ( "ioctl(RTC_ALM_SET)", ARG3, sizeof(struct vki_rtc_time));
|
|
break;
|
|
case VKI_RTC_IRQP_READ:
|
|
PRE_MEM_WRITE( "ioctl(RTC_IRQP_READ)", ARG3, sizeof(unsigned long));
|
|
break;
|
|
|
|
/* Loopback control */
|
|
case VKI_LOOP_CTL_ADD:
|
|
case VKI_LOOP_CTL_REMOVE:
|
|
case VKI_LOOP_CTL_GET_FREE:
|
|
break;
|
|
/* Loopback device */
|
|
case VKI_LOOP_SET_FD:
|
|
case VKI_LOOP_CLR_FD:
|
|
case VKI_LOOP_CHANGE_FD:
|
|
case VKI_LOOP_SET_CAPACITY:
|
|
case VKI_LOOP_SET_DIRECT_IO:
|
|
case VKI_LOOP_SET_BLOCK_SIZE:
|
|
break;
|
|
case VKI_LOOP_SET_STATUS:
|
|
PRE_MEM_READ("ioctl(LOOP_SET_STATUS)", ARG3, sizeof(struct vki_loop_info));
|
|
break;
|
|
case VKI_LOOP_GET_STATUS:
|
|
PRE_MEM_WRITE("ioctl(LOOP_GET_STATUS)", ARG3, sizeof(struct vki_loop_info));
|
|
break;
|
|
case VKI_LOOP_SET_STATUS64:
|
|
PRE_MEM_READ("ioctl(LOOP_SET_STATUS64)", ARG3, sizeof(struct vki_loop_info64));
|
|
break;
|
|
case VKI_LOOP_GET_STATUS64:
|
|
PRE_MEM_WRITE("ioctl(LOOP_GET_STATUS64)", ARG3, sizeof(struct vki_loop_info64));
|
|
break;
|
|
|
|
/* Block devices */
|
|
case VKI_BLKROSET:
|
|
PRE_MEM_READ( "ioctl(BLKROSET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKROGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKROGET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKGETSIZE:
|
|
PRE_MEM_WRITE( "ioctl(BLKGETSIZE)", ARG3, sizeof(unsigned long));
|
|
break;
|
|
case VKI_BLKFLSBUF:
|
|
break;
|
|
case VKI_BLKRASET:
|
|
break;
|
|
case VKI_BLKRAGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKRAGET)", ARG3, sizeof(long));
|
|
break;
|
|
case VKI_BLKFRASET:
|
|
break;
|
|
case VKI_BLKFRAGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKFRAGET)", ARG3, sizeof(long));
|
|
break;
|
|
case VKI_BLKSECTGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKSECTGET)", ARG3, sizeof(unsigned short));
|
|
break;
|
|
case VKI_BLKSSZGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKSSZGET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKBSZGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKBSZGET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKBSZSET:
|
|
PRE_MEM_READ( "ioctl(BLKBSZSET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKGETSIZE64:
|
|
PRE_MEM_WRITE( "ioctl(BLKGETSIZE64)", ARG3, sizeof(unsigned long long));
|
|
break;
|
|
case VKI_BLKPBSZGET:
|
|
PRE_MEM_WRITE( "ioctl(BLKPBSZGET)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKIOMIN:
|
|
PRE_MEM_WRITE( "ioctl(BLKIOMIN)", ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKIOOPT:
|
|
PRE_MEM_WRITE( "ioctl(BLKIOOPT)", ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKALIGNOFF:
|
|
PRE_MEM_WRITE( "ioctl(BLKALIGNOFF)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKDISCARDZEROES:
|
|
PRE_MEM_WRITE( "ioctl(BLKDISCARDZEROES)", ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKREPORTZONE:
|
|
PRE_MEM_READ("ioctl(BLKREPORTZONE)", ARG3,
|
|
sizeof(struct vki_blk_zone_report));
|
|
break;
|
|
case VKI_BLKRESETZONE:
|
|
PRE_MEM_READ("ioctl(BLKRESETZONE)", ARG3,
|
|
sizeof(struct vki_blk_zone_range));
|
|
break;
|
|
|
|
/* Hard disks */
|
|
case VKI_HDIO_GETGEO: /* 0x0301 */
|
|
PRE_MEM_WRITE( "ioctl(HDIO_GETGEO)", ARG3, sizeof(struct vki_hd_geometry));
|
|
break;
|
|
case VKI_HDIO_GET_DMA: /* 0x030b */
|
|
PRE_MEM_WRITE( "ioctl(HDIO_GET_DMA)", ARG3, sizeof(long));
|
|
break;
|
|
case VKI_HDIO_GET_IDENTITY: /* 0x030d */
|
|
PRE_MEM_WRITE( "ioctl(HDIO_GET_IDENTITY)", ARG3,
|
|
VKI_SIZEOF_STRUCT_HD_DRIVEID );
|
|
break;
|
|
|
|
/* SCSI */
|
|
case VKI_SCSI_IOCTL_GET_IDLUN: /* 0x5382 */
|
|
PRE_MEM_WRITE( "ioctl(SCSI_IOCTL_GET_IDLUN)", ARG3, sizeof(struct vki_scsi_idlun));
|
|
break;
|
|
case VKI_SCSI_IOCTL_GET_BUS_NUMBER: /* 0x5386 */
|
|
PRE_MEM_WRITE( "ioctl(SCSI_IOCTL_GET_BUS_NUMBER)", ARG3, sizeof(int));
|
|
break;
|
|
|
|
/* CD ROM stuff (??) */
|
|
case VKI_CDROM_GET_MCN:
|
|
PRE_MEM_READ( "ioctl(CDROM_GET_MCN)", ARG3,
|
|
sizeof(struct vki_cdrom_mcn) );
|
|
break;
|
|
case VKI_CDROM_SEND_PACKET:
|
|
PRE_MEM_READ( "ioctl(CDROM_SEND_PACKET)", ARG3,
|
|
sizeof(struct vki_cdrom_generic_command));
|
|
break;
|
|
case VKI_CDROMSUBCHNL:
|
|
PRE_MEM_READ( "ioctl(CDROMSUBCHNL (cdsc_format, char))",
|
|
(Addr) &(((struct vki_cdrom_subchnl*) (Addr)ARG3)->cdsc_format),
|
|
sizeof(((struct vki_cdrom_subchnl*) (Addr)ARG3)->cdsc_format));
|
|
PRE_MEM_WRITE( "ioctl(CDROMSUBCHNL)", ARG3,
|
|
sizeof(struct vki_cdrom_subchnl));
|
|
break;
|
|
case VKI_CDROMREADMODE1: /*0x530d*/
|
|
PRE_MEM_READ("ioctl(CDROMREADMODE1)", ARG3, VKI_CD_FRAMESIZE_RAW1);
|
|
PRE_MEM_WRITE("ioctl(CDROMREADMODE1)", ARG3, VKI_CD_FRAMESIZE_RAW1);
|
|
break;
|
|
case VKI_CDROMREADMODE2: /*0x530c*/
|
|
PRE_MEM_READ("ioctl(CDROMREADMODE2)", ARG3, VKI_CD_FRAMESIZE_RAW0);
|
|
PRE_MEM_WRITE("ioctl(CDROMREADMODE2)", ARG3, VKI_CD_FRAMESIZE_RAW0);
|
|
break;
|
|
case VKI_CDROMREADTOCHDR:
|
|
PRE_MEM_WRITE( "ioctl(CDROMREADTOCHDR)", ARG3,
|
|
sizeof(struct vki_cdrom_tochdr));
|
|
break;
|
|
case VKI_CDROMREADTOCENTRY:
|
|
PRE_MEM_READ( "ioctl(CDROMREADTOCENTRY (cdte_format, char))",
|
|
(Addr) &(((struct vki_cdrom_tocentry*) (Addr)ARG3)->cdte_format),
|
|
sizeof(((struct vki_cdrom_tocentry*) (Addr)ARG3)->cdte_format));
|
|
PRE_MEM_READ( "ioctl(CDROMREADTOCENTRY (cdte_track, char))",
|
|
(Addr) &(((struct vki_cdrom_tocentry*) (Addr)ARG3)->cdte_track),
|
|
sizeof(((struct vki_cdrom_tocentry*) (Addr)ARG3)->cdte_track));
|
|
PRE_MEM_WRITE( "ioctl(CDROMREADTOCENTRY)", ARG3,
|
|
sizeof(struct vki_cdrom_tocentry));
|
|
break;
|
|
case VKI_CDROMMULTISESSION: /* 0x5310 */
|
|
PRE_MEM_WRITE( "ioctl(CDROMMULTISESSION)", ARG3,
|
|
sizeof(struct vki_cdrom_multisession));
|
|
break;
|
|
case VKI_CDROMVOLREAD: /* 0x5313 */
|
|
PRE_MEM_WRITE( "ioctl(CDROMVOLREAD)", ARG3,
|
|
sizeof(struct vki_cdrom_volctrl));
|
|
break;
|
|
case VKI_CDROMREADRAW: /* 0x5314 */
|
|
PRE_MEM_READ( "ioctl(CDROMREADRAW)", ARG3, sizeof(struct vki_cdrom_msf));
|
|
PRE_MEM_WRITE( "ioctl(CDROMREADRAW)", ARG3, VKI_CD_FRAMESIZE_RAW);
|
|
break;
|
|
case VKI_CDROMREADAUDIO: /* 0x530e */
|
|
PRE_MEM_READ( "ioctl(CDROMREADAUDIO)", ARG3,
|
|
sizeof (struct vki_cdrom_read_audio));
|
|
if ( ARG3 ) {
|
|
/* ToDo: don't do any of the following if the structure is invalid */
|
|
struct vki_cdrom_read_audio *cra =
|
|
(struct vki_cdrom_read_audio *) (Addr)ARG3;
|
|
PRE_MEM_WRITE( "ioctl(CDROMREADAUDIO).buf",
|
|
(Addr)(cra->buf), cra->nframes * VKI_CD_FRAMESIZE_RAW);
|
|
}
|
|
break;
|
|
case VKI_CDROMPLAYMSF:
|
|
PRE_MEM_READ( "ioctl(CDROMPLAYMSF)", ARG3, sizeof(struct vki_cdrom_msf));
|
|
break;
|
|
/* The following two are probably bogus (should check args
|
|
for readability). JRS 20021117 */
|
|
case VKI_CDROM_DRIVE_STATUS: /* 0x5326 */
|
|
case VKI_CDROM_CLEAR_OPTIONS: /* 0x5321 */
|
|
break;
|
|
case VKI_CDROM_GET_CAPABILITY: /* 0x5331 */
|
|
break;
|
|
|
|
case VKI_FIGETBSZ:
|
|
PRE_MEM_WRITE( "ioctl(FIGETBSZ)", ARG3, sizeof(unsigned long));
|
|
break;
|
|
case VKI_FIBMAP:
|
|
PRE_MEM_READ( "ioctl(FIBMAP)", ARG3, sizeof(int));
|
|
break;
|
|
case VKI_FICLONE:
|
|
/* The direction of FICLONE (W) is incorrectly specified
|
|
* as it expects a file descriptor and not a pointer to
|
|
* user data */
|
|
break;
|
|
|
|
case VKI_FBIOGET_VSCREENINFO: /* 0x4600 */
|
|
PRE_MEM_WRITE( "ioctl(FBIOGET_VSCREENINFO)", ARG3,
|
|
sizeof(struct vki_fb_var_screeninfo));
|
|
break;
|
|
case VKI_FBIOPUT_VSCREENINFO:
|
|
PRE_MEM_READ( "ioctl(FBIOPUT_VSCREENINFO)", ARG3,
|
|
sizeof(struct vki_fb_var_screeninfo));
|
|
break;
|
|
case VKI_FBIOGET_FSCREENINFO: /* 0x4602 */
|
|
PRE_MEM_WRITE( "ioctl(FBIOGET_FSCREENINFO)", ARG3,
|
|
sizeof(struct vki_fb_fix_screeninfo));
|
|
break;
|
|
case VKI_FBIOPAN_DISPLAY:
|
|
PRE_MEM_READ( "ioctl(FBIOPAN_DISPLAY)", ARG3,
|
|
sizeof(struct vki_fb_var_screeninfo));
|
|
|
|
break;
|
|
case VKI_PPCLAIM:
|
|
case VKI_PPEXCL:
|
|
case VKI_PPYIELD:
|
|
case VKI_PPRELEASE:
|
|
break;
|
|
case VKI_PPSETMODE:
|
|
PRE_MEM_READ( "ioctl(PPSETMODE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETMODE:
|
|
PRE_MEM_WRITE( "ioctl(PPGETMODE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPSETPHASE:
|
|
PRE_MEM_READ( "ioctl(PPSETPHASE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETPHASE:
|
|
PRE_MEM_WRITE( "ioctl(PPGETPHASE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETMODES:
|
|
PRE_MEM_WRITE( "ioctl(PPGETMODES)", ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_PPSETFLAGS:
|
|
PRE_MEM_READ( "ioctl(PPSETFLAGS)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETFLAGS:
|
|
PRE_MEM_WRITE( "ioctl(PPGETFLAGS)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPRSTATUS:
|
|
PRE_MEM_WRITE( "ioctl(PPRSTATUS)", ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPRDATA:
|
|
PRE_MEM_WRITE( "ioctl(PPRDATA)", ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPRCONTROL:
|
|
PRE_MEM_WRITE( "ioctl(PPRCONTROL)", ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPWDATA:
|
|
PRE_MEM_READ( "ioctl(PPWDATA)", ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPWCONTROL:
|
|
PRE_MEM_READ( "ioctl(PPWCONTROL)", ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPFCONTROL:
|
|
PRE_MEM_READ( "ioctl(PPFCONTROL)", ARG3, 2 * sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPDATADIR:
|
|
PRE_MEM_READ( "ioctl(PPDATADIR)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPNEGOT:
|
|
PRE_MEM_READ( "ioctl(PPNEGOT)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPWCTLONIRQ:
|
|
PRE_MEM_READ( "ioctl(PPWCTLONIRQ)",ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPCLRIRQ:
|
|
PRE_MEM_WRITE( "ioctl(PPCLRIRQ)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPSETTIME:
|
|
PRE_MEM_READ( "ioctl(PPSETTIME)", ARG3, sizeof(struct vki_timeval) );
|
|
break;
|
|
case VKI_PPGETTIME:
|
|
PRE_MEM_WRITE( "ioctl(PPGETTIME)", ARG3, sizeof(struct vki_timeval) );
|
|
break;
|
|
|
|
case VKI_GIO_FONT:
|
|
PRE_MEM_WRITE( "ioctl(GIO_FONT)", ARG3, 32 * 256 );
|
|
break;
|
|
case VKI_PIO_FONT:
|
|
PRE_MEM_READ( "ioctl(PIO_FONT)", ARG3, 32 * 256 );
|
|
break;
|
|
|
|
case VKI_GIO_FONTX:
|
|
PRE_MEM_READ( "ioctl(GIO_FONTX)", ARG3, sizeof(struct vki_consolefontdesc) );
|
|
if ( ARG3 ) {
|
|
/* ToDo: don't do any of the following if the structure is invalid */
|
|
struct vki_consolefontdesc *cfd =
|
|
(struct vki_consolefontdesc *)(Addr)ARG3;
|
|
PRE_MEM_WRITE( "ioctl(GIO_FONTX).chardata", (Addr)cfd->chardata,
|
|
32 * cfd->charcount );
|
|
}
|
|
break;
|
|
case VKI_PIO_FONTX:
|
|
PRE_MEM_READ( "ioctl(PIO_FONTX)", ARG3, sizeof(struct vki_consolefontdesc) );
|
|
if ( ARG3 ) {
|
|
/* ToDo: don't do any of the following if the structure is invalid */
|
|
struct vki_consolefontdesc *cfd =
|
|
(struct vki_consolefontdesc *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(PIO_FONTX).chardata", (Addr)cfd->chardata,
|
|
32 * cfd->charcount );
|
|
}
|
|
break;
|
|
|
|
case VKI_PIO_FONTRESET:
|
|
break;
|
|
|
|
case VKI_GIO_CMAP:
|
|
PRE_MEM_WRITE( "ioctl(GIO_CMAP)", ARG3, 16 * 3 );
|
|
break;
|
|
case VKI_PIO_CMAP:
|
|
PRE_MEM_READ( "ioctl(PIO_CMAP)", ARG3, 16 * 3 );
|
|
break;
|
|
|
|
case VKI_KIOCSOUND:
|
|
case VKI_KDMKTONE:
|
|
break;
|
|
|
|
case VKI_KDGETLED:
|
|
PRE_MEM_WRITE( "ioctl(KDGETLED)", ARG3, sizeof(char) );
|
|
break;
|
|
case VKI_KDSETLED:
|
|
break;
|
|
|
|
case VKI_KDGKBTYPE:
|
|
PRE_MEM_WRITE( "ioctl(KDGKBTYPE)", ARG3, sizeof(char) );
|
|
break;
|
|
|
|
case VKI_KDADDIO:
|
|
case VKI_KDDELIO:
|
|
case VKI_KDENABIO:
|
|
case VKI_KDDISABIO:
|
|
break;
|
|
|
|
case VKI_KDSETMODE:
|
|
break;
|
|
case VKI_KDGETMODE:
|
|
PRE_MEM_WRITE( "ioctl(KDGETMODE)", ARG3, sizeof(int) );
|
|
break;
|
|
|
|
case VKI_KDMAPDISP:
|
|
case VKI_KDUNMAPDISP:
|
|
break;
|
|
|
|
case VKI_GIO_SCRNMAP:
|
|
PRE_MEM_WRITE( "ioctl(GIO_SCRNMAP)", ARG3, VKI_E_TABSZ );
|
|
break;
|
|
case VKI_PIO_SCRNMAP:
|
|
PRE_MEM_READ( "ioctl(PIO_SCRNMAP)", ARG3, VKI_E_TABSZ );
|
|
break;
|
|
case VKI_GIO_UNISCRNMAP:
|
|
PRE_MEM_WRITE( "ioctl(GIO_UNISCRNMAP)", ARG3,
|
|
VKI_E_TABSZ * sizeof(unsigned short) );
|
|
break;
|
|
case VKI_PIO_UNISCRNMAP:
|
|
PRE_MEM_READ( "ioctl(PIO_UNISCRNMAP)", ARG3,
|
|
VKI_E_TABSZ * sizeof(unsigned short) );
|
|
break;
|
|
|
|
case VKI_GIO_UNIMAP:
|
|
if ( ARG3 ) {
|
|
struct vki_unimapdesc *desc = (struct vki_unimapdesc *) (Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(GIO_UNIMAP)", (Addr)&desc->entry_ct,
|
|
sizeof(unsigned short));
|
|
PRE_MEM_READ( "ioctl(GIO_UNIMAP)", (Addr)&desc->entries,
|
|
sizeof(struct vki_unipair *));
|
|
PRE_MEM_WRITE( "ioctl(GIO_UNIMAP).entries", (Addr)desc->entries,
|
|
desc->entry_ct * sizeof(struct vki_unipair));
|
|
}
|
|
break;
|
|
case VKI_PIO_UNIMAP:
|
|
if ( ARG3 ) {
|
|
struct vki_unimapdesc *desc = (struct vki_unimapdesc *) (Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(GIO_UNIMAP)", (Addr)&desc->entry_ct,
|
|
sizeof(unsigned short) );
|
|
PRE_MEM_READ( "ioctl(GIO_UNIMAP)", (Addr)&desc->entries,
|
|
sizeof(struct vki_unipair *) );
|
|
PRE_MEM_READ( "ioctl(PIO_UNIMAP).entries", (Addr)desc->entries,
|
|
desc->entry_ct * sizeof(struct vki_unipair) );
|
|
}
|
|
break;
|
|
case VKI_PIO_UNIMAPCLR:
|
|
PRE_MEM_READ( "ioctl(GIO_UNIMAP)", ARG3, sizeof(struct vki_unimapinit));
|
|
break;
|
|
|
|
case VKI_KDGKBMODE:
|
|
PRE_MEM_WRITE( "ioctl(KDGKBMODE)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_KDSKBMODE:
|
|
break;
|
|
|
|
case VKI_KDGKBMETA:
|
|
PRE_MEM_WRITE( "ioctl(KDGKBMETA)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_KDSKBMETA:
|
|
break;
|
|
|
|
case VKI_KDGKBLED:
|
|
PRE_MEM_WRITE( "ioctl(KDGKBLED)", ARG3, sizeof(char) );
|
|
break;
|
|
case VKI_KDSKBLED:
|
|
break;
|
|
|
|
case VKI_KDGKBENT:
|
|
PRE_MEM_READ( "ioctl(KDGKBENT).kb_table",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_table,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_table) );
|
|
PRE_MEM_READ( "ioctl(KDGKBENT).kb_index",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_index,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_index) );
|
|
PRE_MEM_WRITE( "ioctl(KDGKBENT).kb_value",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_value,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_value) );
|
|
break;
|
|
case VKI_KDSKBENT:
|
|
PRE_MEM_READ( "ioctl(KDSKBENT).kb_table",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_table,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_table) );
|
|
PRE_MEM_READ( "ioctl(KDSKBENT).kb_index",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_index,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_index) );
|
|
PRE_MEM_READ( "ioctl(KDSKBENT).kb_value",
|
|
(Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_value,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_value) );
|
|
break;
|
|
|
|
case VKI_KDGKBSENT:
|
|
PRE_MEM_READ( "ioctl(KDGKBSENT).kb_func",
|
|
(Addr)&((struct vki_kbsentry *)(Addr)ARG3)->kb_func,
|
|
sizeof(((struct vki_kbsentry *)(Addr)ARG3)->kb_func) );
|
|
PRE_MEM_WRITE( "ioctl(KDGKSENT).kb_string",
|
|
(Addr)((struct vki_kbsentry *)(Addr)ARG3)->kb_string,
|
|
sizeof(((struct vki_kbsentry *)(Addr)ARG3)->kb_string) );
|
|
break;
|
|
case VKI_KDSKBSENT:
|
|
PRE_MEM_READ( "ioctl(KDSKBSENT).kb_func",
|
|
(Addr)&((struct vki_kbsentry *)(Addr)ARG3)->kb_func,
|
|
sizeof(((struct vki_kbsentry *)(Addr)ARG3)->kb_func) );
|
|
PRE_MEM_RASCIIZ( "ioctl(KDSKBSENT).kb_string",
|
|
(Addr)((struct vki_kbsentry *)(Addr)ARG3)->kb_string );
|
|
break;
|
|
|
|
case VKI_KDGKBDIACR:
|
|
PRE_MEM_WRITE( "ioctl(KDGKBDIACR)", ARG3, sizeof(struct vki_kbdiacrs) );
|
|
break;
|
|
case VKI_KDSKBDIACR:
|
|
PRE_MEM_READ( "ioctl(KDSKBDIACR)", ARG3, sizeof(struct vki_kbdiacrs) );
|
|
break;
|
|
|
|
case VKI_KDGETKEYCODE:
|
|
PRE_MEM_READ( "ioctl(KDGETKEYCODE).scancode",
|
|
(Addr)&((struct vki_kbkeycode *)(Addr)ARG3)->scancode,
|
|
sizeof(((struct vki_kbkeycode *)(Addr)ARG3)->scancode) );
|
|
PRE_MEM_WRITE( "ioctl(KDGETKEYCODE).keycode",
|
|
(Addr)((struct vki_kbkeycode *)(Addr)ARG3)->keycode,
|
|
sizeof(((struct vki_kbkeycode *)(Addr)ARG3)->keycode) );
|
|
break;
|
|
case VKI_KDSETKEYCODE:
|
|
PRE_MEM_READ( "ioctl(KDSETKEYCODE).scancode",
|
|
(Addr)&((struct vki_kbkeycode *)(Addr)ARG3)->scancode,
|
|
sizeof(((struct vki_kbkeycode *)(Addr)ARG3)->scancode) );
|
|
PRE_MEM_READ( "ioctl(KDSETKEYCODE).keycode",
|
|
(Addr)((struct vki_kbkeycode *)(Addr)ARG3)->keycode,
|
|
sizeof(((struct vki_kbkeycode *)(Addr)ARG3)->keycode) );
|
|
break;
|
|
|
|
case VKI_KDSIGACCEPT:
|
|
break;
|
|
|
|
case VKI_KDKBDREP:
|
|
PRE_MEM_READ( "ioctl(KBKBDREP)", ARG3, sizeof(struct vki_kbd_repeat) );
|
|
break;
|
|
|
|
case VKI_KDFONTOP:
|
|
if ( ARG3 ) {
|
|
struct vki_console_font_op *op =
|
|
(struct vki_console_font_op *) (Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(KDFONTOP)", (Addr)op,
|
|
sizeof(struct vki_console_font_op) );
|
|
switch ( op->op ) {
|
|
case VKI_KD_FONT_OP_SET:
|
|
PRE_MEM_READ( "ioctl(KDFONTOP,KD_FONT_OP_SET).data",
|
|
(Addr)op->data,
|
|
(op->width + 7) / 8 * 32 * op->charcount );
|
|
break;
|
|
case VKI_KD_FONT_OP_GET:
|
|
if ( op->data )
|
|
PRE_MEM_WRITE( "ioctl(KDFONTOP,KD_FONT_OP_GET).data",
|
|
(Addr)op->data,
|
|
(op->width + 7) / 8 * 32 * op->charcount );
|
|
break;
|
|
case VKI_KD_FONT_OP_SET_DEFAULT:
|
|
if ( op->data )
|
|
PRE_MEM_RASCIIZ( "ioctl(KDFONTOP,KD_FONT_OP_SET_DEFAULT).data",
|
|
(Addr)op->data );
|
|
break;
|
|
case VKI_KD_FONT_OP_COPY:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VKI_VT_OPENQRY:
|
|
PRE_MEM_WRITE( "ioctl(VT_OPENQRY)", ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_VT_GETMODE:
|
|
PRE_MEM_WRITE( "ioctl(VT_GETMODE)", ARG3, sizeof(struct vki_vt_mode) );
|
|
break;
|
|
case VKI_VT_SETMODE:
|
|
PRE_MEM_READ( "ioctl(VT_SETMODE)", ARG3, sizeof(struct vki_vt_mode) );
|
|
break;
|
|
case VKI_VT_GETSTATE:
|
|
PRE_MEM_WRITE( "ioctl(VT_GETSTATE).v_active",
|
|
(Addr) &(((struct vki_vt_stat*) (Addr)ARG3)->v_active),
|
|
sizeof(((struct vki_vt_stat*) (Addr)ARG3)->v_active));
|
|
PRE_MEM_WRITE( "ioctl(VT_GETSTATE).v_state",
|
|
(Addr) &(((struct vki_vt_stat*) (Addr)ARG3)->v_state),
|
|
sizeof(((struct vki_vt_stat*) (Addr)ARG3)->v_state));
|
|
break;
|
|
case VKI_VT_RELDISP:
|
|
case VKI_VT_ACTIVATE:
|
|
case VKI_VT_WAITACTIVE:
|
|
case VKI_VT_DISALLOCATE:
|
|
break;
|
|
case VKI_VT_RESIZE:
|
|
PRE_MEM_READ( "ioctl(VT_RESIZE)", ARG3, sizeof(struct vki_vt_sizes) );
|
|
break;
|
|
case VKI_VT_RESIZEX:
|
|
PRE_MEM_READ( "ioctl(VT_RESIZEX)", ARG3, sizeof(struct vki_vt_consize) );
|
|
break;
|
|
case VKI_VT_LOCKSWITCH:
|
|
case VKI_VT_UNLOCKSWITCH:
|
|
break;
|
|
|
|
case VKI_USBDEVFS_CONTROL:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_ctrltransfer *vkuc =
|
|
(struct vki_usbdevfs_ctrltransfer *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).bRequestType", (Addr)&vkuc->bRequestType, sizeof(vkuc->bRequestType));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).bRequest", (Addr)&vkuc->bRequest, sizeof(vkuc->bRequest));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).wValue", (Addr)&vkuc->wValue, sizeof(vkuc->wValue));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).wIndex", (Addr)&vkuc->wIndex, sizeof(vkuc->wIndex));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).wLength", (Addr)&vkuc->wLength, sizeof(vkuc->wLength));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).timeout", (Addr)&vkuc->timeout, sizeof(vkuc->timeout));
|
|
if (vkuc->bRequestType & 0x80)
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_CONTROL).data", (Addr)vkuc->data, vkuc->wLength);
|
|
else
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_CONTROL).data", (Addr)vkuc->data, vkuc->wLength);
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_BULK:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_bulktransfer *vkub =
|
|
(struct vki_usbdevfs_bulktransfer *)(Addr)ARG3;
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_BULK)", ARG3, sizeof(struct vki_usbdevfs_bulktransfer));
|
|
if (vkub->ep & 0x80)
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_BULK).data", (Addr)vkub->data, vkub->len);
|
|
else
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_BULK).data", (Addr)vkub->data, vkub->len);
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_GETDRIVER:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_getdriver *vkugd =
|
|
(struct vki_usbdevfs_getdriver *) (Addr)ARG3;
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_GETDRIVER)", (Addr)&vkugd->driver, sizeof(vkugd->driver));
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_SUBMITURB:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_urb *vkuu = (struct vki_usbdevfs_urb *)(Addr)ARG3;
|
|
|
|
/* Not the whole struct needs to be initialized */
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).endpoint", (Addr)&vkuu->endpoint, sizeof(vkuu->endpoint));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).type", (Addr)&vkuu->type, sizeof(vkuu->type));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).flags", (Addr)&vkuu->flags, sizeof(vkuu->flags));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)&vkuu->buffer, sizeof(vkuu->buffer));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).signr", (Addr)&vkuu->signr, sizeof(vkuu->signr));
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).status", (Addr)&vkuu->status, sizeof(vkuu->status));
|
|
if (vkuu->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
|
|
struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)vkuu->buffer;
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.setup_packet", (Addr)vkusp, sizeof(*vkusp));
|
|
if (vkusp->bRequestType & 0x80)
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
|
|
else
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
|
|
} else if (vkuu->type == VKI_USBDEVFS_URB_TYPE_ISO) {
|
|
int total_length = 0;
|
|
int i;
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).number_of_packets", (Addr)&vkuu->number_of_packets, sizeof(vkuu->number_of_packets));
|
|
for(i=0; i<vkuu->number_of_packets; i++) {
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].length", (Addr)&vkuu->iso_frame_desc[i].length, sizeof(vkuu->iso_frame_desc[i].length));
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].actual_length", (Addr)&vkuu->iso_frame_desc[i].actual_length, sizeof(vkuu->iso_frame_desc[i].actual_length));
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].status", (Addr)&vkuu->iso_frame_desc[i].status, sizeof(vkuu->iso_frame_desc[i].status));
|
|
total_length += vkuu->iso_frame_desc[i].length;
|
|
}
|
|
if (vkuu->endpoint & 0x80)
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
|
|
else
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).error_count", (Addr)&vkuu->error_count, sizeof(vkuu->error_count));
|
|
} else {
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
|
|
if (vkuu->endpoint & 0x80)
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
|
|
else
|
|
PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
|
|
}
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_DISCARDURB:
|
|
break;
|
|
case VKI_USBDEVFS_REAPURB:
|
|
if ( ARG3 ) {
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURB)", ARG3, sizeof(struct vki_usbdevfs_urb **));
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_REAPURBNDELAY:
|
|
if ( ARG3 ) {
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURBNDELAY)", ARG3, sizeof(struct vki_usbdevfs_urb **));
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_CONNECTINFO:
|
|
PRE_MEM_WRITE( "ioctl(USBDEVFS_CONNECTINFO)", ARG3, sizeof(struct vki_usbdevfs_connectinfo));
|
|
break;
|
|
case VKI_USBDEVFS_IOCTL:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_ioctl *vkui =
|
|
(struct vki_usbdevfs_ioctl *)(Addr)ARG3;
|
|
UInt dir2, size2;
|
|
PRE_MEM_READ("ioctl(USBDEVFS_IOCTL)", (Addr)vkui, sizeof(struct vki_usbdevfs_ioctl));
|
|
dir2 = _VKI_IOC_DIR(vkui->ioctl_code);
|
|
size2 = _VKI_IOC_SIZE(vkui->ioctl_code);
|
|
if (size2 > 0) {
|
|
if (dir2 & _VKI_IOC_WRITE)
|
|
PRE_MEM_READ("ioctl(USBDEVFS_IOCTL).dataWrite", (Addr)vkui->data, size2);
|
|
else if (dir2 & _VKI_IOC_READ)
|
|
PRE_MEM_WRITE("ioctl(USBDEVFS_IOCTL).dataRead", (Addr)vkui->data, size2);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_RESET:
|
|
break;
|
|
|
|
/* I2C (/dev/i2c-*) ioctls */
|
|
case VKI_I2C_SLAVE:
|
|
case VKI_I2C_SLAVE_FORCE:
|
|
case VKI_I2C_TENBIT:
|
|
case VKI_I2C_PEC:
|
|
break;
|
|
case VKI_I2C_FUNCS:
|
|
PRE_MEM_WRITE( "ioctl(I2C_FUNCS)", ARG3, sizeof(unsigned long) );
|
|
break;
|
|
case VKI_I2C_RDWR:
|
|
if ( ARG3 ) {
|
|
struct vki_i2c_rdwr_ioctl_data *vkui =
|
|
(struct vki_i2c_rdwr_ioctl_data *)(Addr)ARG3;
|
|
UInt i;
|
|
PRE_MEM_READ("ioctl(I2C_RDWR)", (Addr)vkui, sizeof(struct vki_i2c_rdwr_ioctl_data));
|
|
for (i=0; i < vkui->nmsgs; i++) {
|
|
struct vki_i2c_msg *msg = vkui->msgs + i;
|
|
PRE_MEM_READ("ioctl(I2C_RDWR).msgs", (Addr)msg, sizeof(struct vki_i2c_msg));
|
|
if (msg->flags & VKI_I2C_M_RD)
|
|
PRE_MEM_WRITE("ioctl(I2C_RDWR).msgs.buf", (Addr)msg->buf, msg->len);
|
|
else
|
|
PRE_MEM_READ("ioctl(I2C_RDWR).msgs.buf", (Addr)msg->buf, msg->len);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_I2C_SMBUS:
|
|
if ( ARG3 ) {
|
|
struct vki_i2c_smbus_ioctl_data *vkis
|
|
= (struct vki_i2c_smbus_ioctl_data *) (Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.read_write",
|
|
(Addr)&vkis->read_write, sizeof(vkis->read_write));
|
|
PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.size",
|
|
(Addr)&vkis->size, sizeof(vkis->size));
|
|
PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.command",
|
|
(Addr)&vkis->command, sizeof(vkis->command));
|
|
/* i2c_smbus_write_quick hides its value in read_write, so
|
|
this variable can have a different meaning */
|
|
/* to make matters worse i2c_smbus_write_byte stores its
|
|
value in command */
|
|
if ( ! ((vkis->size == VKI_I2C_SMBUS_QUICK) ||
|
|
((vkis->size == VKI_I2C_SMBUS_BYTE)
|
|
&& (vkis->read_write == VKI_I2C_SMBUS_WRITE)))) {
|
|
/* the rest uses the byte array to store the data,
|
|
some the first byte for size */
|
|
UInt size;
|
|
switch(vkis->size) {
|
|
case VKI_I2C_SMBUS_BYTE_DATA:
|
|
size = 1;
|
|
break;
|
|
case VKI_I2C_SMBUS_WORD_DATA:
|
|
case VKI_I2C_SMBUS_PROC_CALL:
|
|
size = 2;
|
|
break;
|
|
case VKI_I2C_SMBUS_BLOCK_DATA:
|
|
case VKI_I2C_SMBUS_I2C_BLOCK_BROKEN:
|
|
case VKI_I2C_SMBUS_BLOCK_PROC_CALL:
|
|
case VKI_I2C_SMBUS_I2C_BLOCK_DATA:
|
|
size = 1 + vkis->data->block[0];
|
|
break;
|
|
default:
|
|
size = 0;
|
|
}
|
|
|
|
if ((vkis->read_write == VKI_I2C_SMBUS_READ)
|
|
|| (vkis->size == VKI_I2C_SMBUS_PROC_CALL)
|
|
|| (vkis->size == VKI_I2C_SMBUS_BLOCK_PROC_CALL))
|
|
PRE_MEM_WRITE("ioctl(VKI_I2C_SMBUS)"
|
|
".i2c_smbus_ioctl_data.data",
|
|
(Addr)&vkis->data->block[0], size);
|
|
else
|
|
PRE_MEM_READ("ioctl(VKI_I2C_SMBUS)."
|
|
"i2c_smbus_ioctl_data.data",
|
|
(Addr)&vkis->data->block[0], size);
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Wireless extensions ioctls */
|
|
case VKI_SIOCSIWCOMMIT:
|
|
case VKI_SIOCSIWNWID:
|
|
case VKI_SIOCSIWFREQ:
|
|
case VKI_SIOCSIWMODE:
|
|
case VKI_SIOCSIWSENS:
|
|
case VKI_SIOCSIWRANGE:
|
|
case VKI_SIOCSIWPRIV:
|
|
case VKI_SIOCSIWSTATS:
|
|
case VKI_SIOCSIWSPY:
|
|
case VKI_SIOCSIWTHRSPY:
|
|
case VKI_SIOCSIWAP:
|
|
case VKI_SIOCSIWSCAN:
|
|
case VKI_SIOCSIWESSID:
|
|
case VKI_SIOCSIWRATE:
|
|
case VKI_SIOCSIWNICKN:
|
|
case VKI_SIOCSIWRTS:
|
|
case VKI_SIOCSIWFRAG:
|
|
case VKI_SIOCSIWTXPOW:
|
|
case VKI_SIOCSIWRETRY:
|
|
case VKI_SIOCSIWENCODE:
|
|
case VKI_SIOCSIWPOWER:
|
|
case VKI_SIOCSIWGENIE:
|
|
case VKI_SIOCSIWMLME:
|
|
case VKI_SIOCSIWAUTH:
|
|
case VKI_SIOCSIWENCODEEXT:
|
|
case VKI_SIOCSIWPMKSA:
|
|
break;
|
|
case VKI_SIOCGIWNAME:
|
|
if (ARG3) {
|
|
PRE_MEM_WRITE("ioctl(SIOCGIWNAME)",
|
|
(Addr)((struct vki_iwreq *)(Addr)ARG3)->u.name,
|
|
sizeof(((struct vki_iwreq *)(Addr)ARG3)->u.name));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWNWID:
|
|
case VKI_SIOCGIWSENS:
|
|
case VKI_SIOCGIWRATE:
|
|
case VKI_SIOCGIWRTS:
|
|
case VKI_SIOCGIWFRAG:
|
|
case VKI_SIOCGIWTXPOW:
|
|
case VKI_SIOCGIWRETRY:
|
|
case VKI_SIOCGIWPOWER:
|
|
case VKI_SIOCGIWAUTH:
|
|
if (ARG3) {
|
|
PRE_MEM_WRITE("ioctl(SIOCGIW[NWID|SENS|RATE|RTS|FRAG|TXPOW|"
|
|
"RETRY|PARAM|AUTH])",
|
|
(Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.nwid,
|
|
sizeof(struct vki_iw_param));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWFREQ:
|
|
if (ARG3) {
|
|
PRE_MEM_WRITE("ioctl(SIOCGIWFREQ",
|
|
(Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.freq,
|
|
sizeof(struct vki_iw_freq));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWMODE:
|
|
if (ARG3) {
|
|
PRE_MEM_WRITE("ioctl(SIOCGIWMODE",
|
|
(Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.mode,
|
|
sizeof(__vki_u32));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWRANGE:
|
|
case VKI_SIOCGIWPRIV:
|
|
case VKI_SIOCGIWSTATS:
|
|
case VKI_SIOCGIWSPY:
|
|
case VKI_SIOCGIWTHRSPY:
|
|
case VKI_SIOCGIWAPLIST:
|
|
case VKI_SIOCGIWSCAN:
|
|
case VKI_SIOCGIWESSID:
|
|
case VKI_SIOCGIWNICKN:
|
|
case VKI_SIOCGIWENCODE:
|
|
case VKI_SIOCGIWGENIE:
|
|
case VKI_SIOCGIWENCODEEXT:
|
|
if (ARG3) {
|
|
struct vki_iw_point* point;
|
|
point = &((struct vki_iwreq *)(Addr)ARG3)->u.data;
|
|
PRE_MEM_WRITE("ioctl(SIOCGIW[RANGE|PRIV|STATS|SPY|THRSPY|"
|
|
"APLIST|SCAN|ESSID|NICKN|ENCODE|GENIE|ENCODEEXT])",
|
|
(Addr)point->pointer, point->length);
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWAP:
|
|
if (ARG3) {
|
|
PRE_MEM_WRITE("ioctl(SIOCGIWAP)",
|
|
(Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.ap_addr,
|
|
sizeof(struct vki_sockaddr));
|
|
}
|
|
break;
|
|
|
|
/* User input device creation */
|
|
case VKI_UI_SET_EVBIT:
|
|
case VKI_UI_SET_KEYBIT:
|
|
case VKI_UI_SET_RELBIT:
|
|
case VKI_UI_SET_ABSBIT:
|
|
case VKI_UI_SET_MSCBIT:
|
|
case VKI_UI_SET_LEDBIT:
|
|
case VKI_UI_SET_SNDBIT:
|
|
case VKI_UI_SET_FFBIT:
|
|
case VKI_UI_SET_SWBIT:
|
|
case VKI_UI_SET_PROPBIT:
|
|
/* These just take an int by value */
|
|
break;
|
|
|
|
# if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
|
|
|| defined(VGPV_mips32_linux_android) \
|
|
|| defined(VGPV_arm64_linux_android)
|
|
/* ashmem */
|
|
case VKI_ASHMEM_GET_SIZE:
|
|
case VKI_ASHMEM_SET_SIZE:
|
|
case VKI_ASHMEM_GET_PROT_MASK:
|
|
case VKI_ASHMEM_SET_PROT_MASK:
|
|
case VKI_ASHMEM_GET_PIN_STATUS:
|
|
case VKI_ASHMEM_PURGE_ALL_CACHES:
|
|
break;
|
|
case VKI_ASHMEM_GET_NAME:
|
|
PRE_MEM_WRITE( "ioctl(ASHMEM_SET_NAME)", ARG3, VKI_ASHMEM_NAME_LEN );
|
|
break;
|
|
case VKI_ASHMEM_SET_NAME:
|
|
PRE_MEM_RASCIIZ( "ioctl(ASHMEM_SET_NAME)", ARG3);
|
|
break;
|
|
case VKI_ASHMEM_PIN:
|
|
case VKI_ASHMEM_UNPIN:
|
|
PRE_MEM_READ( "ioctl(ASHMEM_PIN|ASHMEM_UNPIN)",
|
|
ARG3, sizeof(struct vki_ashmem_pin) );
|
|
break;
|
|
|
|
/* binder */
|
|
case VKI_BINDER_WRITE_READ:
|
|
if (ARG3) {
|
|
struct vki_binder_write_read* bwr
|
|
= (struct vki_binder_write_read*)(Addr)ARG3;
|
|
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).write_buffer",
|
|
bwr->write_buffer);
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).write_size",
|
|
bwr->write_size);
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).write_consumed",
|
|
bwr->write_consumed);
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).read_buffer",
|
|
bwr->read_buffer);
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).read_size",
|
|
bwr->read_size);
|
|
PRE_FIELD_READ("ioctl(BINDER_WRITE_READ).read_consumed",
|
|
bwr->read_consumed);
|
|
|
|
PRE_FIELD_WRITE("ioctl(BINDER_WRITE_READ).write_consumed",
|
|
bwr->write_consumed);
|
|
PRE_FIELD_WRITE("ioctl(BINDER_WRITE_READ).read_consumed",
|
|
bwr->read_consumed);
|
|
|
|
if (bwr->read_size)
|
|
PRE_MEM_WRITE("ioctl(BINDER_WRITE_READ).read_buffer[]",
|
|
(Addr)bwr->read_buffer, bwr->read_size);
|
|
if (bwr->write_size)
|
|
PRE_MEM_READ("ioctl(BINDER_WRITE_READ).write_buffer[]",
|
|
(Addr)bwr->write_buffer, bwr->write_size);
|
|
}
|
|
break;
|
|
|
|
case VKI_BINDER_SET_IDLE_TIMEOUT:
|
|
case VKI_BINDER_SET_MAX_THREADS:
|
|
case VKI_BINDER_SET_IDLE_PRIORITY:
|
|
case VKI_BINDER_SET_CONTEXT_MGR:
|
|
case VKI_BINDER_THREAD_EXIT:
|
|
break;
|
|
case VKI_BINDER_VERSION:
|
|
if (ARG3) {
|
|
struct vki_binder_version* bv =
|
|
(struct vki_binder_version*)(Addr)ARG3;
|
|
PRE_FIELD_WRITE("ioctl(BINDER_VERSION)", bv->protocol_version);
|
|
}
|
|
break;
|
|
# endif /* defined(VGPV_*_linux_android) */
|
|
|
|
case VKI_HCIGETDEVLIST:
|
|
if (ARG3) {
|
|
struct vki_hci_dev_list_req* dlr =
|
|
(struct vki_hci_dev_list_req*)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(HCIGETDEVLIST)",
|
|
(Addr)ARG3, sizeof(struct vki_hci_dev_list_req));
|
|
PRE_MEM_WRITE("ioctl(HCIGETDEVLIST)",
|
|
(Addr)ARG3 + sizeof(struct vki_hci_dev_list_req),
|
|
dlr->dev_num * sizeof(struct vki_hci_dev_req));
|
|
}
|
|
break;
|
|
|
|
case VKI_HCIINQUIRY:
|
|
if (ARG3) {
|
|
struct vki_hci_inquiry_req* ir =
|
|
(struct vki_hci_inquiry_req*)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(HCIINQUIRY)",
|
|
(Addr)ARG3, sizeof(struct vki_hci_inquiry_req));
|
|
PRE_MEM_WRITE("ioctl(HCIINQUIRY)",
|
|
(Addr)ARG3 + sizeof(struct vki_hci_inquiry_req),
|
|
ir->num_rsp * sizeof(struct vki_inquiry_info));
|
|
}
|
|
break;
|
|
|
|
case VKI_DRM_IOCTL_VERSION:
|
|
if (ARG3) {
|
|
struct vki_drm_version* data = (struct vki_drm_version *)(Addr)ARG3;
|
|
struct vg_drm_version_info* info;
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).version_major", (Addr)&data->version_major, sizeof(data->version_major));
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).version_minor", (Addr)&data->version_minor, sizeof(data->version_minor));
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).version_patchlevel", (Addr)&data->version_patchlevel, sizeof(data->version_patchlevel));
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).name_len", (Addr)&data->name_len, sizeof(data->name_len));
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).name", (Addr)&data->name, sizeof(data->name));
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).name", (Addr)data->name, data->name_len);
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).date_len", (Addr)&data->date_len, sizeof(data->date_len));
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).date", (Addr)&data->date, sizeof(data->date));
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).date", (Addr)data->date, data->date_len);
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).desc_len", (Addr)&data->desc_len, sizeof(data->desc_len));
|
|
PRE_MEM_READ("ioctl(DRM_VERSION).desc", (Addr)&data->desc, sizeof(data->desc));
|
|
PRE_MEM_WRITE("ioctl(DRM_VERSION).desc", (Addr)data->desc, data->desc_len);
|
|
info = VG_(malloc)("syswrap.ioctl.1", sizeof(*info));
|
|
// To ensure we VG_(free) info even when syscall fails:
|
|
*flags |= SfPostOnFail;
|
|
info->data = *data;
|
|
info->orig = data;
|
|
ARG3 = (Addr)&info->data;
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GET_UNIQUE:
|
|
if (ARG3) {
|
|
struct vki_drm_unique *data = (struct vki_drm_unique *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_GET_UNIQUE).unique_len", (Addr)&data->unique_len, sizeof(data->unique_len));
|
|
PRE_MEM_READ("ioctl(DRM_GET_UNIQUE).unique", (Addr)&data->unique, sizeof(data->unique));
|
|
PRE_MEM_WRITE("ioctl(DRM_GET_UNIQUE).unique", (Addr)data->unique, data->unique_len);
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GET_MAGIC:
|
|
if (ARG3) {
|
|
struct vki_drm_auth *data = (struct vki_drm_auth *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(DRM_GET_MAGIC).magic", (Addr)&data->magic, sizeof(data->magic));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_WAIT_VBLANK:
|
|
if (ARG3) {
|
|
union vki_drm_wait_vblank *data =
|
|
(union vki_drm_wait_vblank *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_WAIT_VBLANK).request.type", (Addr)&data->request.type, sizeof(data->request.type));
|
|
PRE_MEM_READ("ioctl(DRM_WAIT_VBLANK).request.sequence", (Addr)&data->request.sequence, sizeof(data->request.sequence));
|
|
/* XXX: It seems request.signal isn't used */
|
|
PRE_MEM_WRITE("ioctl(DRM_WAIT_VBLANK).reply", (Addr)&data->reply, sizeof(data->reply));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GEM_CLOSE:
|
|
if (ARG3) {
|
|
struct vki_drm_gem_close *data =
|
|
(struct vki_drm_gem_close *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_GEM_CLOSE).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GEM_FLINK:
|
|
if (ARG3) {
|
|
struct vki_drm_gem_flink *data =
|
|
(struct vki_drm_gem_flink *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_GEM_FLINK).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_WRITE("ioctl(DRM_GEM_FLINK).name", (Addr)&data->name, sizeof(data->name));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GEM_OPEN:
|
|
if (ARG3) {
|
|
struct vki_drm_gem_open *data = (struct vki_drm_gem_open *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_GEM_OPEN).name", (Addr)&data->name, sizeof(data->name));
|
|
PRE_MEM_WRITE("ioctl(DRM_GEM_OPEN).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_WRITE("ioctl(DRM_GEM_OPEN).size", (Addr)&data->size, sizeof(data->size));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GETPARAM:
|
|
if (ARG3) {
|
|
vki_drm_i915_getparam_t *data = (vki_drm_i915_getparam_t *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GETPARAM).param", (Addr)&data->param, sizeof(data->param));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GETPARAM).value", (Addr)data->value, sizeof(int));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_BUSY:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_busy *data =
|
|
(struct vki_drm_i915_gem_busy *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_BUSY).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_BUSY).busy", (Addr)&data->busy, sizeof(data->busy));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_CREATE:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_create *data =
|
|
(struct vki_drm_i915_gem_create *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_CREATE).size", (Addr)&data->size, sizeof(data->size));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_CREATE).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_PREAD:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_pread *data =
|
|
(struct vki_drm_i915_gem_pread *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PREAD).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PREAD).offset", (Addr)&data->offset, sizeof(data->offset));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PREAD).size", (Addr)&data->size, sizeof(data->size));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PREAD).data_ptr", (Addr)&data->data_ptr, sizeof(data->data_ptr));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_PREAD).data_ptr", (Addr)data->data_ptr, data->size);
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_PWRITE:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_pwrite *data =
|
|
(struct vki_drm_i915_gem_pwrite *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PWRITE).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PWRITE).offset", (Addr)&data->offset, sizeof(data->offset));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PWRITE).size", (Addr)&data->size, sizeof(data->size));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_PWRITE).data_ptr", (Addr)&data->data_ptr, sizeof(data->data_ptr));
|
|
/* PRE_MEM_READ("ioctl(DRM_I915_GEM_PWRITE).data_ptr", (Addr)data->data_ptr, data->size);
|
|
* NB: the buffer is allowed to contain any amount of uninitialized data (e.g.
|
|
* interleaved vertex attributes may have a wide stride with uninitialized data between
|
|
* consecutive vertices) */
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAPv1:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap_v1 *data =
|
|
(struct vki_drm_i915_gem_mmap_v1 *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAPv1).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAPv1).offset", (Addr)&data->offset, sizeof(data->offset));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAPv1).size", (Addr)&data->size, sizeof(data->size));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_MMAPv1).addr_ptr", (Addr)&data->addr_ptr, sizeof(data->addr_ptr));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAP:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap *data =
|
|
(struct vki_drm_i915_gem_mmap *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAP).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAP).offset", (Addr)&data->offset, sizeof(data->offset));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAP).size", (Addr)&data->size, sizeof(data->size));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAP).flags", (Addr)&data->size, sizeof(data->flags));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_MMAP).addr_ptr", (Addr)&data->addr_ptr, sizeof(data->addr_ptr));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAP_GTT:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap_gtt *data =
|
|
(struct vki_drm_i915_gem_mmap_gtt *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_MMAP_GTT).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_MMAP_GTT).offset", (Addr)&data->offset, sizeof(data->offset));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_SET_DOMAIN:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_set_domain *data =
|
|
(struct vki_drm_i915_gem_set_domain *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_DOMAIN).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_DOMAIN).read_domains", (Addr)&data->read_domains, sizeof(data->read_domains));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_DOMAIN).write_domain", (Addr)&data->write_domain, sizeof(data->write_domain));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_SET_TILING:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_set_tiling *data =
|
|
(struct vki_drm_i915_gem_set_tiling *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_TILING).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_TILING).tiling_mode", (Addr)&data->tiling_mode, sizeof(data->tiling_mode));
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_SET_TILING).stride", (Addr)&data->stride, sizeof(data->stride));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_SET_TILING).swizzle_mode", (Addr)&data->swizzle_mode, sizeof(data->swizzle_mode));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_GET_TILING:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_get_tiling *data =
|
|
(struct vki_drm_i915_gem_get_tiling *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(DRM_I915_GEM_GET_TILING).handle", (Addr)&data->handle, sizeof(data->handle));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_GET_TILING).tiling_mode", (Addr)&data->tiling_mode, sizeof(data->tiling_mode));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_GET_TILING).swizzle_mode", (Addr)&data->swizzle_mode, sizeof(data->swizzle_mode));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_GET_APERTURE:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_get_aperture *data =
|
|
(struct vki_drm_i915_gem_get_aperture *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_GET_APERTURE).aper_size", (Addr)&data->aper_size, sizeof(data->aper_size));
|
|
PRE_MEM_WRITE("ioctl(DRM_I915_GEM_GET_APERTURE).aper_available_size", (Addr)&data->aper_available_size, sizeof(data->aper_available_size));
|
|
}
|
|
break;
|
|
|
|
/* KVM ioctls that check for a numeric value as parameter */
|
|
case VKI_KVM_GET_API_VERSION:
|
|
case VKI_KVM_CREATE_VM:
|
|
case VKI_KVM_GET_VCPU_MMAP_SIZE:
|
|
case VKI_KVM_CHECK_EXTENSION:
|
|
case VKI_KVM_SET_TSS_ADDR:
|
|
case VKI_KVM_CREATE_VCPU:
|
|
case VKI_KVM_RUN:
|
|
break;
|
|
|
|
case VKI_KVM_S390_MEM_OP: {
|
|
struct vki_kvm_s390_mem_op *args =
|
|
(struct vki_kvm_s390_mem_op *)(Addr)(ARG3);
|
|
PRE_MEM_READ("ioctl(KVM_S390_MEM_OP)", ARG3,
|
|
sizeof(struct vki_kvm_s390_mem_op));
|
|
if (args->flags & VKI_KVM_S390_MEMOP_F_CHECK_ONLY)
|
|
break;
|
|
if (args->op == VKI_KVM_S390_MEMOP_LOGICAL_READ)
|
|
PRE_MEM_WRITE("ioctl(KVM_S390_MEM_OP).buf", (Addr)args->buf, args->size);
|
|
if (args->op == VKI_KVM_S390_MEMOP_LOGICAL_WRITE)
|
|
PRE_MEM_READ("ioctl(KVM_S390_MEM_OP).buf", (Addr)args->buf, args->size);
|
|
}
|
|
break;
|
|
|
|
|
|
#ifdef ENABLE_XEN
|
|
case VKI_XEN_IOCTL_PRIVCMD_HYPERCALL: {
|
|
SyscallArgs harrghs;
|
|
struct vki_xen_privcmd_hypercall *args =
|
|
(struct vki_xen_privcmd_hypercall *)(Addr)(ARG3);
|
|
|
|
if (!args)
|
|
break;
|
|
|
|
VG_(memset)(&harrghs, 0, sizeof(harrghs));
|
|
harrghs.sysno = args->op;
|
|
harrghs.arg1 = args->arg[0];
|
|
harrghs.arg2 = args->arg[1];
|
|
harrghs.arg3 = args->arg[2];
|
|
harrghs.arg4 = args->arg[3];
|
|
harrghs.arg5 = args->arg[4];
|
|
harrghs.arg6 = harrghs.arg7 = harrghs.arg8 = 0;
|
|
|
|
WRAPPER_PRE_NAME(xen, hypercall) (tid, layout, &harrghs, status, flags);
|
|
|
|
/* HACK. arg8 is used to return the number of hypercall
|
|
* arguments actually consumed! */
|
|
PRE_MEM_READ("hypercall", ARG3, sizeof(args->op) +
|
|
( sizeof(args->arg[0]) * harrghs.arg8 ) );
|
|
|
|
break;
|
|
}
|
|
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAP: {
|
|
struct vki_xen_privcmd_mmap *args =
|
|
(struct vki_xen_privcmd_mmap *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP(num)",
|
|
(Addr)&args->num, sizeof(args->num));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP(dom)",
|
|
(Addr)&args->dom, sizeof(args->dom));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP(entry)",
|
|
(Addr)args->entry, sizeof(*(args->entry)) * args->num);
|
|
break;
|
|
}
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH: {
|
|
struct vki_xen_privcmd_mmapbatch *args =
|
|
(struct vki_xen_privcmd_mmapbatch *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH(num)",
|
|
(Addr)&args->num, sizeof(args->num));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH(dom)",
|
|
(Addr)&args->dom, sizeof(args->dom));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH(addr)",
|
|
(Addr)&args->addr, sizeof(args->addr));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH(arr)",
|
|
(Addr)args->arr, sizeof(*(args->arr)) * args->num);
|
|
break;
|
|
}
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2: {
|
|
struct vki_xen_privcmd_mmapbatch_v2 *args =
|
|
(struct vki_xen_privcmd_mmapbatch_v2 *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2(num)",
|
|
(Addr)&args->num, sizeof(args->num));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2(dom)",
|
|
(Addr)&args->dom, sizeof(args->dom));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2(addr)",
|
|
(Addr)&args->addr, sizeof(args->addr));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2(arr)",
|
|
(Addr)args->arr, sizeof(*(args->arr)) * args->num);
|
|
break;
|
|
}
|
|
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_VIRQ: {
|
|
struct vki_xen_ioctl_evtchn_bind_virq *args =
|
|
(struct vki_xen_ioctl_evtchn_bind_virq *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_BIND_VIRQ(virq)",
|
|
(Addr)&args->virq, sizeof(args->virq));
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_INTERDOMAIN: {
|
|
struct vki_xen_ioctl_evtchn_bind_interdomain *args =
|
|
(struct vki_xen_ioctl_evtchn_bind_interdomain *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_BIND_INTERDOMAIN(remote_domain)",
|
|
(Addr)&args->remote_domain, sizeof(args->remote_domain));
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_BIND_INTERDOMAIN(remote_port)",
|
|
(Addr)&args->remote_port, sizeof(args->remote_port));
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
|
|
struct vki_xen_ioctl_evtchn_bind_unbound_port *args =
|
|
(struct vki_xen_ioctl_evtchn_bind_unbound_port *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_BIND_UNBOUND_PORT(remote_domain)",
|
|
(Addr)&args->remote_domain, sizeof(args->remote_domain));
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_EVTCHN_UNBIND: {
|
|
struct vki_xen_ioctl_evtchn_unbind *args =
|
|
(struct vki_xen_ioctl_evtchn_unbind *)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_UNBIND(port)",
|
|
(Addr)&args->port, sizeof(args->port));
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_EVTCHN_NOTIFY: {
|
|
struct vki_xen_ioctl_evtchn_notify *args =
|
|
(struct vki_xen_ioctl_evtchn_notify*)(Addr)(ARG3);
|
|
PRE_MEM_READ("VKI_XEN_IOCTL_EVTCHN_notify(port)",
|
|
(Addr)&args->port, sizeof(args->port));
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_EVTCHN_RESET:
|
|
/* No input*/
|
|
break;
|
|
#endif
|
|
|
|
/* Lustre */
|
|
case VKI_OBD_IOC_FID2PATH: {
|
|
struct vki_getinfo_fid2path *gf =
|
|
(struct vki_getinfo_fid2path *)(Addr)ARG3;
|
|
PRE_MEM_READ("VKI_OBD_IOC_FID2PATH(args)", ARG3, sizeof(struct vki_getinfo_fid2path));
|
|
PRE_FIELD_WRITE("VKI_OBD_IOC_FID2PATH(args).gf_recno", gf->gf_recno);
|
|
PRE_FIELD_WRITE("VKI_OBD_IOC_FID2PATH(args).gf_linkno", gf->gf_linkno);
|
|
PRE_MEM_WRITE("VKI_OBD_IOC_FID2PATH(args)", (Addr)gf->gf_path, gf->gf_pathlen);
|
|
break;
|
|
}
|
|
|
|
case VKI_LL_IOC_PATH2FID:
|
|
PRE_MEM_WRITE("ioctl(VKI_LL_IOC_PATH2FID)", ARG3, sizeof(struct vki_lu_fid));
|
|
break;
|
|
|
|
case VKI_LL_IOC_GETPARENT: {
|
|
struct vki_getparent *gp = (struct vki_getparent *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_LL_IOC_GETPARENT).gp_linkno", gp->gp_linkno);
|
|
PRE_FIELD_READ("ioctl(VKI_LL_IOC_GETPARENT).gp_name_size", gp->gp_name_size);
|
|
PRE_FIELD_WRITE("ioctl(VKI_LL_IOC_GETPARENT).gp_fid", gp->gp_fid);
|
|
PRE_MEM_WRITE("ioctl(VKI_LL_IOC_GETPARENT).gp_name", (Addr)gp->gp_name, gp->gp_name_size);
|
|
break;
|
|
}
|
|
|
|
/* V4L2 */
|
|
case VKI_V4L2_QUERYCAP: {
|
|
struct vki_v4l2_capability *data =
|
|
(struct vki_v4l2_capability *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERYCAP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FMT: {
|
|
struct vki_v4l2_fmtdesc *data = (struct vki_v4l2_fmtdesc *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FMT).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FMT).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FMT).flags", data->flags);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FMT).description", data->description);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FMT).pixelformat", data->pixelformat);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FMT).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FMT: {
|
|
struct vki_v4l2_format *data = (struct vki_v4l2_format *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FMT).type", data->type);
|
|
switch (data->type) {
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FMT).fmt.pix.priv", data->fmt.pix.priv);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.pix", data->fmt.pix);
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_G_FMT)",
|
|
(Addr)&data->type + sizeof(data->type) + sizeof(data->fmt.pix),
|
|
sizeof(*data) - sizeof(data->type) - sizeof(data->fmt.pix));
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.vbi", data->fmt.vbi);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.sliced", data->fmt.sliced);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FMT).fmt.win.clips", data->fmt.win.clips);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FMT).fmt.win.bitmap", data->fmt.win.bitmap);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FMT).fmt.win.clipcount", data->fmt.win.clipcount);
|
|
if (data->fmt.win.clipcount && data->fmt.win.clips)
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.clips[]",
|
|
(Addr)data->fmt.win.clips,
|
|
data->fmt.win.clipcount * sizeof(data->fmt.win.clips[0]));
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.clipcount", data->fmt.win.clipcount);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.w", data->fmt.win.w);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.field", data->fmt.win.field);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.chromakey", data->fmt.win.chromakey);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.win.global_alpha", data->fmt.win.global_alpha);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.pix_mp", data->fmt.pix_mp);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FMT).fmt.sdr", data->fmt.sdr);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_FMT: {
|
|
struct vki_v4l2_format *data = (struct vki_v4l2_format *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).type", data->type);
|
|
switch (data->type) {
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_FMT)",
|
|
(Addr)&data->type + sizeof(data->type),
|
|
sizeof(*data) - sizeof(data->type));
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).fmt.vbi", data->fmt.vbi);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).fmt.sliced", data->fmt.sliced);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).fmt.win", data->fmt.win);
|
|
if (data->fmt.win.clipcount && data->fmt.win.clips)
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_FMT).fmt.win.clips[]",
|
|
(Addr)data->fmt.win.clips,
|
|
data->fmt.win.clipcount * sizeof(data->fmt.win.clips[0]));
|
|
if (data->fmt.win.bitmap)
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_FMT).fmt.win.bitmap[]",
|
|
(Addr)data->fmt.win.bitmap,
|
|
data->fmt.win.w.height * ((data->fmt.win.w.width + 7) / 8));
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).fmt.pix_mp", data->fmt.pix_mp);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FMT).fmt.sdr", data->fmt.sdr);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_FMT: {
|
|
struct vki_v4l2_format *data = (struct vki_v4l2_format *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).type", data->type);
|
|
switch (data->type) {
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_FMT)",
|
|
(Addr)&data->type + sizeof(data->type),
|
|
sizeof(*data) - sizeof(data->type));
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.vbi", data->fmt.vbi);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.sliced", data->fmt.sliced);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.win", data->fmt.win);
|
|
if (data->fmt.win.clipcount && data->fmt.win.clips)
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.win.clips[]",
|
|
(Addr)data->fmt.win.clips,
|
|
data->fmt.win.clipcount * sizeof(data->fmt.win.clips[0]));
|
|
if (data->fmt.win.bitmap)
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.win.bitmap[]",
|
|
(Addr)data->fmt.win.bitmap,
|
|
data->fmt.win.w.height * ((data->fmt.win.w.width + 7) / 8));
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.pix_mp", data->fmt.pix_mp);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_FMT).fmt.sdr", data->fmt.sdr);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_REQBUFS: {
|
|
struct vki_v4l2_requestbuffers *data =
|
|
(struct vki_v4l2_requestbuffers *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_REQBUFS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYBUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).reserved2", data->reserved2);
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).length", data->length);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYBUF).m.planes", data->m.planes);
|
|
for (i = 0; i < data->length; i++) {
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m.planes[].bytesused", data->m.planes[i].bytesused);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m.planes[].length", data->m.planes[i].length);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m.planes[].m", data->m.planes[i].m);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m.planes[].data_offset", data->m.planes[i].data_offset);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m.planes[].reserved", data->m.planes[i].reserved);
|
|
}
|
|
} else {
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).m", data->m);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).length", data->length);
|
|
}
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).bytesused", data->bytesused);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).flags", data->flags);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).field", data->field);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).timestamp", data->timestamp);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).timecode", data->timecode);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).sequence", data->sequence);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).memory", data->memory);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QUERYBUF).sequence", data->sequence);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FBUF: {
|
|
struct vki_v4l2_framebuffer *data =
|
|
(struct vki_v4l2_framebuffer *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_FBUF)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_FBUF: {
|
|
struct vki_v4l2_framebuffer *data =
|
|
(struct vki_v4l2_framebuffer *)(Addr)ARG3;
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_S_FBUF).capability", data->capability);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FBUF).flags", data->flags);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FBUF).base", data->base);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_FBUF).fmt", data->fmt);
|
|
break;
|
|
}
|
|
case VKI_V4L2_OVERLAY: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_OVERLAY)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QBUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
int is_output = data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VBI_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).flags", data->flags);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).memory", data->memory);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).reserved2", data->reserved2);
|
|
if (is_output) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).bytesused", data->bytesused);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).field", data->field);
|
|
}
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).length", data->length);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes", data->m.planes);
|
|
for (i = 0; i < data->length; i++) {
|
|
if (is_output) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes[].bytesused", data->m.planes[i].bytesused);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes[].data_offset", data->m.planes[i].data_offset);
|
|
}
|
|
if (data->memory == VKI_V4L2_MEMORY_MMAP)
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QBUF).m.planes[].m", data->m.planes[i].m);
|
|
else if (data->memory == VKI_V4L2_MEMORY_DMABUF)
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes[].m.fd", data->m.planes[i].m.fd);
|
|
else
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes[].m", data->m.planes[i].m);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.planes[].reserved", data->m.planes[i].reserved);
|
|
}
|
|
} else {
|
|
if (data->memory == VKI_V4L2_MEMORY_MMAP)
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_QBUF).m", data->m);
|
|
else if (data->memory == VKI_V4L2_MEMORY_DMABUF)
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m.fd", data->m.fd);
|
|
else
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).m", data->m);
|
|
if (is_output) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).bytesused", data->bytesused);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).field", data->field);
|
|
}
|
|
}
|
|
if (is_output && (data->flags & VKI_V4L2_BUF_FLAG_TIMESTAMP_MASK) == VKI_V4L2_BUF_FLAG_TIMESTAMP_COPY) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).timestamp", data->timestamp);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QBUF).timecode", data->timecode);
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_EXPBUF: {
|
|
struct vki_v4l2_exportbuffer *data =
|
|
(struct vki_v4l2_exportbuffer *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_EXPBUF).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_EXPBUF).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_EXPBUF).plane", data->plane);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_EXPBUF).flags", data->flags);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_EXPBUF).fd", data->fd);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_EXPBUF).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DQBUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).memory", data->memory);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).reserved2", data->reserved2);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).bytesused", data->bytesused);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).field", data->field);
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).length", data->length);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).m.planes", data->m.planes);
|
|
for (i = 0; i < data->length; i++) {
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).m.planes[].bytesused", data->m.planes[i].bytesused);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).m.planes[].data_offset", data->m.planes[i].data_offset);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).m.planes[].length", data->m.planes[i].length);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).m.planes[].m", data->m.planes[i].m);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DQBUF).m.planes[].reserved", data->m.planes[i].reserved);
|
|
}
|
|
} else {
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).m", data->m);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).length", data->length);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).bytesused", data->bytesused);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).field", data->field);
|
|
}
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).timestamp", data->timestamp);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).timecode", data->timecode);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DQBUF).sequence", data->sequence);
|
|
break;
|
|
}
|
|
case VKI_V4L2_STREAMON: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_STREAMON)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_STREAMOFF: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_STREAMOFF)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_PARM: {
|
|
struct vki_v4l2_streamparm *data =
|
|
(struct vki_v4l2_streamparm *)(Addr)ARG3;
|
|
int is_output = data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VBI_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_PARM).type", data->type);
|
|
if (is_output) {
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_PARM)", (Addr)&data->parm.output,
|
|
sizeof(data->parm.output) - sizeof(data->parm.output.reserved));
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_PARM).parm.output.reserved", data->parm.output.reserved);
|
|
} else {
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_PARM)", (Addr)&data->parm.capture,
|
|
sizeof(data->parm.capture) - sizeof(data->parm.capture.reserved));
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_PARM).parm.capture.reserved", data->parm.capture.reserved);
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_PARM: {
|
|
struct vki_v4l2_streamparm *data =
|
|
(struct vki_v4l2_streamparm *)(Addr)ARG3;
|
|
int is_output = data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VBI_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_PARM).type", data->type);
|
|
if (is_output)
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_PARM).parm.output", data->parm.output);
|
|
else
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_PARM).parm.capture", data->parm.capture);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_STD: {
|
|
vki_v4l2_std_id *data = (vki_v4l2_std_id *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_STD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_STD: {
|
|
vki_v4l2_std_id *data = (vki_v4l2_std_id *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_STD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMSTD: {
|
|
struct vki_v4l2_standard *data = (struct vki_v4l2_standard *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMSTD).index", data->index);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_ENUMSTD)", (Addr)&data->id, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMINPUT: {
|
|
struct vki_v4l2_input *data = (struct vki_v4l2_input *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMINPUT).index", data->index);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_ENUMINPUT)", (Addr)data->name, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_CTRL: {
|
|
struct vki_v4l2_control *data = (struct vki_v4l2_control *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_CTRL).id", data->id);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_CTRL).value", data->value);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_CTRL: {
|
|
struct vki_v4l2_control *data = (struct vki_v4l2_control *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_CTRL)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_TUNER: {
|
|
struct vki_v4l2_tuner *data = (struct vki_v4l2_tuner *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_TUNER).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_TUNER).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_TUNER)", (Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_TUNER: {
|
|
struct vki_v4l2_tuner *data = (struct vki_v4l2_tuner *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_TUNER).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_TUNER).audmode", data->audmode);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_TUNER).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_AUDIO: {
|
|
struct vki_v4l2_audio *data = (struct vki_v4l2_audio *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_AUDIO)", (Addr)data,
|
|
sizeof(*data) - sizeof(data->reserved));
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_AUDIO).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_AUDIO: {
|
|
struct vki_v4l2_audio *data = (struct vki_v4l2_audio *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDIO).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDIO).mode", data->mode);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDIO).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYCTRL: {
|
|
struct vki_v4l2_queryctrl *data = (struct vki_v4l2_queryctrl *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYCTRL).id", data->id);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERYCTRL)", (Addr)&data->type,
|
|
sizeof(*data) - sizeof(data->id));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYMENU: {
|
|
struct vki_v4l2_querymenu *data = (struct vki_v4l2_querymenu *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYMENU).id", data->id);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERYMENU).index", data->index);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERYMENU)", (Addr)data->name,
|
|
sizeof(*data) - sizeof(data->id) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_INPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_INPUT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_INPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_INPUT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_EDID: {
|
|
struct vki_v4l2_edid *data = (struct vki_v4l2_edid *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_G_EDID)", (Addr)data, sizeof(*data));
|
|
if (data->blocks && data->edid)
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_EDID)", (Addr)data->edid, data->blocks * 128);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_EDID: {
|
|
struct vki_v4l2_edid *data = (struct vki_v4l2_edid *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_EDID)", (Addr)data, sizeof(*data));
|
|
if (data->blocks && data->edid)
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_EDID)", (Addr)data->edid, data->blocks * 128);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_OUTPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_OUTPUT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_OUTPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_OUTPUT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMOUTPUT: {
|
|
struct vki_v4l2_output *data = (struct vki_v4l2_output *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMOUTPUT).index", data->index);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_ENUMOUTPUT)", (Addr)data->name, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_AUDOUT: {
|
|
struct vki_v4l2_audioout *data = (struct vki_v4l2_audioout *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_AUDOUT)", (Addr)data,
|
|
sizeof(*data) - sizeof(data->reserved));
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_AUDOUT).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_AUDOUT: {
|
|
struct vki_v4l2_audioout *data = (struct vki_v4l2_audioout *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDOUT).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDOUT).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_AUDOUT).mode", data->mode);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_MODULATOR: {
|
|
struct vki_v4l2_modulator *data = (struct vki_v4l2_modulator *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_MODULATOR).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_MODULATOR).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_MODULATOR)", (Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_MODULATOR: {
|
|
struct vki_v4l2_modulator *data = (struct vki_v4l2_modulator *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_MODULATOR).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_MODULATOR).txsubchans", data->txsubchans);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_MODULATOR).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FREQUENCY: {
|
|
struct vki_v4l2_frequency *data = (struct vki_v4l2_frequency *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FREQUENCY).tuner", data->tuner);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_FREQUENCY).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FREQUENCY).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_FREQUENCY).frequency", data->frequency);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_FREQUENCY: {
|
|
struct vki_v4l2_frequency *data = (struct vki_v4l2_frequency *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_FREQUENCY)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_CROPCAP: {
|
|
struct vki_v4l2_cropcap *data = (struct vki_v4l2_cropcap *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CROPCAP)", data->type);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_CROPCAP)", (Addr)&data->bounds, sizeof(*data) - sizeof(data->type));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_CROP: {
|
|
struct vki_v4l2_crop *data = (struct vki_v4l2_crop *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_CROP).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_CROP).c", data->c);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_CROP: {
|
|
struct vki_v4l2_crop *data = (struct vki_v4l2_crop *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_CROP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_JPEGCOMP: {
|
|
struct vki_v4l2_jpegcompression *data =
|
|
(struct vki_v4l2_jpegcompression *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_JPEGCOMP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_JPEGCOMP: {
|
|
struct vki_v4l2_jpegcompression *data =
|
|
(struct vki_v4l2_jpegcompression *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_JPEGCOMP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYSTD: {
|
|
vki_v4l2_std_id *data = (vki_v4l2_std_id *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERYSTD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMAUDIO: {
|
|
struct vki_v4l2_audio *data = (struct vki_v4l2_audio *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMAUDIO).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMAUDIO).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_ENUMAUDIO)", (Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMAUDOUT: {
|
|
struct vki_v4l2_audioout *data = (struct vki_v4l2_audioout *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMAUDOUT).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUMAUDOUT).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_ENUMAUDOUT)", (Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_PRIORITY: {
|
|
__vki_u32 *data = (__vki_u32 *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_PRIORITY)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_PRIORITY: {
|
|
__vki_u32 *data = (__vki_u32 *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_PRIORITY)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_SLICED_VBI_CAP: {
|
|
struct vki_v4l2_sliced_vbi_cap *data =
|
|
(struct vki_v4l2_sliced_vbi_cap *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SLICED_VBI_CAP).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SLICED_VBI_CAP).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_SLICED_VBI_CAP)", (Addr)data,
|
|
sizeof(*data) - sizeof(data->type) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).ctrl_class", data->ctrl_class);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).count", data->count);
|
|
if (data->count) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).controls", data->controls);
|
|
for (i = 0; i < data->count; i++) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].id", data->controls[i].id);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].size", data->controls[i].size);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].reserved2", data->controls[i].reserved2);
|
|
if (data->controls[i].size) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].ptr", data->controls[i].ptr);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].ptr[]",
|
|
(Addr)data->controls[i].ptr, data->controls[i].size);
|
|
} else {
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_EXT_CTRLS).controls[].value64",
|
|
data->controls[i].value64);
|
|
}
|
|
}
|
|
}
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_EXT_CTRLS).error_idx", data->error_idx);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_EXT_CTRLS).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_EXT_CTRLS).ctrl_class", data->ctrl_class);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_EXT_CTRLS).count", data->count);
|
|
if (data->count) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_EXT_CTRLS).controls", data->controls);
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_EXT_CTRLS)", (Addr)data->controls,
|
|
data->count * sizeof(data->controls[0]));
|
|
for (i = 0; i < data->count; i++) {
|
|
if (data->controls[i].size) {
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_EXT_CTRLS).controls[].ptr[]",
|
|
(Addr)data->controls[i].ptr, data->controls[i].size);
|
|
}
|
|
}
|
|
}
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_S_EXT_CTRLS).error_idx", data->error_idx);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_EXT_CTRLS).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS).ctrl_class", data->ctrl_class);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS).count", data->count);
|
|
if (data->count) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS).controls", data->controls);
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS)", (Addr)data->controls,
|
|
data->count * sizeof(data->controls[0]));
|
|
for (i = 0; i < data->count; i++) {
|
|
if (data->controls[i].size) {
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS).controls[].ptr[]",
|
|
(Addr)data->controls[i].ptr, data->controls[i].size);
|
|
}
|
|
}
|
|
}
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_TRY_EXT_CTRLS).error_idx", data->error_idx);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_TRY_EXT_CTRLS).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FRAMESIZES: {
|
|
struct vki_v4l2_frmsizeenum *data =
|
|
(struct vki_v4l2_frmsizeenum *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMESIZES).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMESIZES).pixel_format", data->pixel_format);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMESIZES).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FRAMESIZES).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FRAMESIZES).stepwise", data->stepwise);
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FRAMEINTERVALS: {
|
|
struct vki_v4l2_frmivalenum *data =
|
|
(struct vki_v4l2_frmivalenum *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).pixel_format", data->pixel_format);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).width", data->width);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).height", data->height);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).type", data->type);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FRAMEINTERVALS).stepwise", data->stepwise);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_ENC_INDEX: {
|
|
struct vki_v4l2_enc_idx *data = (struct vki_v4l2_enc_idx *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_ENC_INDEX)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENCODER_CMD: {
|
|
struct vki_v4l2_encoder_cmd *data =
|
|
(struct vki_v4l2_encoder_cmd *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_ENCODER_CMD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_ENCODER_CMD: {
|
|
struct vki_v4l2_encoder_cmd *data =
|
|
(struct vki_v4l2_encoder_cmd *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_ENCODER_CMD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_S_REGISTER: {
|
|
struct vki_v4l2_dbg_register *data =
|
|
(struct vki_v4l2_dbg_register *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_S_REGISTER).match.type", data->match.type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_S_REGISTER).match.addr", data->match.addr);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_S_REGISTER).reg", data->reg);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_S_REGISTER).val", data->val);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DBG_S_REGISTER).size", data->size);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_G_REGISTER: {
|
|
struct vki_v4l2_dbg_register *data =
|
|
(struct vki_v4l2_dbg_register *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_REGISTER).match.type", data->match.type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_REGISTER).match.addr", data->match.addr);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_REGISTER).reg", data->reg);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DBG_G_REGISTER).val", data->val);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DBG_G_REGISTER).size", data->size);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_HW_FREQ_SEEK: {
|
|
struct vki_v4l2_hw_freq_seek *data =
|
|
(struct vki_v4l2_hw_freq_seek *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_HW_FREQ_SEEK)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_DV_TIMINGS: {
|
|
struct vki_v4l2_dv_timings *data =
|
|
(struct vki_v4l2_dv_timings *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_DV_TIMINGS).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_S_DV_TIMINGS).bt", data->bt);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_DV_TIMINGS: {
|
|
struct vki_v4l2_dv_timings *data =
|
|
(struct vki_v4l2_dv_timings *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_G_DV_TIMINGS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DQEVENT: {
|
|
struct vki_v4l2_event *data = (struct vki_v4l2_event *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_DQEVENT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBSCRIBE_EVENT: {
|
|
struct vki_v4l2_event_subscription *data =
|
|
(struct vki_v4l2_event_subscription *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_SUBSCRIBE_EVENT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_UNSUBSCRIBE_EVENT: {
|
|
struct vki_v4l2_event_subscription *data =
|
|
(struct vki_v4l2_event_subscription *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_UNSUBSCRIBE_EVENT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_CREATE_BUFS: {
|
|
struct vki_v4l2_create_buffers *data =
|
|
(struct vki_v4l2_create_buffers *)(Addr)ARG3;
|
|
struct vki_v4l2_format *fmt = &data->format;
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_CREATE_BUFS).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).count", data->count);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).memory", data->memory);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.type", fmt->type);
|
|
switch (fmt->type) {
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.pix", fmt->fmt.raw_data);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.vbi", fmt->fmt.vbi);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.sliced", fmt->fmt.sliced);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.win", fmt->fmt.win);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.pix_mp", fmt->fmt.pix_mp);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_CREATE_BUFS).format.sdr", fmt->fmt.sdr);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_PREPARE_BUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).memory", data->memory);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).reserved", data->reserved);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).reserved2", data->reserved2);
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).length", data->length);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).m.planes", data->m.planes);
|
|
for (i = 0; i < data->length; i++) {
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_PREPARE_BUF).m.planes[].reserved", data->m.planes[i].reserved);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_SELECTION: {
|
|
struct vki_v4l2_selection *data = (struct vki_v4l2_selection *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SELECTION).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SELECTION).target", data->target);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SELECTION).flags", data->flags);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_G_SELECTION).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_G_SELECTION).r", data->r);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_SELECTION: {
|
|
struct vki_v4l2_selection *data = (struct vki_v4l2_selection *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_S_SELECTION)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DECODER_CMD: {
|
|
struct vki_v4l2_decoder_cmd *data =
|
|
(struct vki_v4l2_decoder_cmd *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_DECODER_CMD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_DECODER_CMD: {
|
|
struct vki_v4l2_decoder_cmd *data =
|
|
(struct vki_v4l2_decoder_cmd *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_TRY_DECODER_CMD)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_DV_TIMINGS: {
|
|
struct vki_v4l2_enum_dv_timings *data =
|
|
(struct vki_v4l2_enum_dv_timings *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_DV_TIMINGS).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_DV_TIMINGS).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_DV_TIMINGS).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_DV_TIMINGS).timings", data->timings);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERY_DV_TIMINGS: {
|
|
struct vki_v4l2_dv_timings *data =
|
|
(struct vki_v4l2_dv_timings *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERY_DV_TIMINGS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DV_TIMINGS_CAP: {
|
|
struct vki_v4l2_dv_timings_cap *data =
|
|
(struct vki_v4l2_dv_timings_cap *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_DV_TIMINGS_CAP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FREQ_BANDS: {
|
|
struct vki_v4l2_frequency_band *data =
|
|
(struct vki_v4l2_frequency_band *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).tuner", data->tuner);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).type", data->type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).capability", data->capability);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).rangelow", data->rangelow);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).rangehigh", data->rangehigh);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_ENUM_FREQ_BANDS).modulation", data->modulation);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_G_CHIP_INFO: {
|
|
struct vki_v4l2_dbg_chip_info *data =
|
|
(struct vki_v4l2_dbg_chip_info *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_CHIP_INFO).match.type", data->match.type);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_CHIP_INFO).match.addr", data->match.addr);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DBG_G_CHIP_INFO).name", data->name);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_DBG_G_CHIP_INFO).flags", data->flags);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_DBG_G_CHIP_INFO).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERY_EXT_CTRL: {
|
|
struct vki_v4l2_query_ext_ctrl *data =
|
|
(struct vki_v4l2_query_ext_ctrl *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERY_EXT_CTRL).id", data->id);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_QUERY_EXT_CTRL).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_V4L2_QUERY_EXT_CTRL)", (Addr)&data->type,
|
|
sizeof(*data) - sizeof(data->id) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_FMT: {
|
|
struct vki_v4l2_subdev_format *data =
|
|
(struct vki_v4l2_subdev_format *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_FMT).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_FMT).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_FMT).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_G_FMT).format", data->format);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_S_FMT: {
|
|
struct vki_v4l2_subdev_format *data =
|
|
(struct vki_v4l2_subdev_format *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_SUBDEV_S_FMT)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_FRAME_INTERVAL: {
|
|
struct vki_v4l2_subdev_frame_interval *data =
|
|
(struct vki_v4l2_subdev_frame_interval *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_FRAME_SIZE).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_FRAME_SIZE).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_G_FRAME_SIZE).interval", data->interval);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_S_FRAME_INTERVAL: {
|
|
struct vki_v4l2_subdev_frame_interval *data =
|
|
(struct vki_v4l2_subdev_frame_interval *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_SUBDEV_S_FRAME_INTERVAL)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_MBUS_CODE: {
|
|
struct vki_v4l2_subdev_mbus_code_enum *data =
|
|
(struct vki_v4l2_subdev_mbus_code_enum *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_MBUS_CODE).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_MBUS_CODE).pad", data->pad);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_MBUS_CODE).code", data->code);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_MBUS_CODE).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_MBUS_CODE).reserved", data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE: {
|
|
struct vki_v4l2_subdev_frame_size_enum *data =
|
|
(struct vki_v4l2_subdev_frame_size_enum *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).code", data->code);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).min_width", data->min_width);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).min_height", data->min_height);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).max_width", data->max_width);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE).max_height", data->max_height);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL: {
|
|
struct vki_v4l2_subdev_frame_interval_enum *data =
|
|
(struct vki_v4l2_subdev_frame_interval_enum *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).index", data->index);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).code", data->code);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).width", data->width);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).height", data->height);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL).interval", data->interval);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_CROP: {
|
|
struct vki_v4l2_subdev_crop *data =
|
|
(struct vki_v4l2_subdev_crop *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_CROP).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_CROP).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_CROP).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_G_CROP).rect", data->rect);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_S_CROP: {
|
|
struct vki_v4l2_subdev_crop *data =
|
|
(struct vki_v4l2_subdev_crop *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_SUBDEV_S_CROP)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_SELECTION: {
|
|
struct vki_v4l2_subdev_selection *data =
|
|
(struct vki_v4l2_subdev_selection *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).pad", data->pad);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).which", data->which);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).target", data->target);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).flags", data->flags);
|
|
PRE_FIELD_READ("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).reserved", data->reserved);
|
|
PRE_FIELD_WRITE("ioctl(VKI_V4L2_SUBDEV_G_SELECTION).r", data->r);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_S_SELECTION: {
|
|
struct vki_v4l2_subdev_selection *data =
|
|
(struct vki_v4l2_subdev_selection *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_V4L2_SUBDEV_S_SELECTION)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_DEVICE_INFO: {
|
|
struct vki_media_device_info *data =
|
|
(struct vki_media_device_info *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_MEDIA_IOC_DEVICE_INFO).reserved", data->reserved);
|
|
PRE_MEM_WRITE("ioctl(VKI_MEDIA_IOC_DEVICE_INFO)",
|
|
(Addr)data, sizeof(*data) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_ENUM_ENTITIES: {
|
|
struct vki_media_entity_desc *data =
|
|
(struct vki_media_entity_desc *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(VKI_MEDIA_IOC_ENUM_ENTITIES).id", data->id);
|
|
PRE_MEM_WRITE("ioctl(VKI_MEDIA_IOC_ENUM_ENTITIES)",
|
|
(Addr)data->name, sizeof(*data) - sizeof(data->id));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_ENUM_LINKS: {
|
|
struct vki_media_links_enum *data =
|
|
(struct vki_media_links_enum *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_MEDIA_IOC_ENUM_LINKS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_SETUP_LINK: {
|
|
struct vki_media_link_desc *data =
|
|
(struct vki_media_link_desc *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_MEDIA_IOC_SETUP_LINK)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
|
|
/* Serial */
|
|
case VKI_TIOCGSERIAL: {
|
|
struct vki_serial_struct *data = (struct vki_serial_struct *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(VKI_TIOCGSERIAL)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_TIOCSSERIAL: {
|
|
struct vki_serial_struct *data = (struct vki_serial_struct *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(VKI_TIOCSSERIAL)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
|
|
case VKI_PERF_EVENT_IOC_RESET:
|
|
case VKI_PERF_EVENT_IOC_REFRESH:
|
|
case VKI_PERF_EVENT_IOC_SET_OUTPUT:
|
|
case VKI_PERF_EVENT_IOC_SET_BPF:
|
|
/* These take scalar arguments, so already handled above */
|
|
break;
|
|
|
|
case VKI_PERF_EVENT_IOC_PERIOD:
|
|
PRE_MEM_READ("ioctl(VKI_PERF_EVENT_IOC_PERIOD)", (Addr)ARG3, sizeof(__vki_u64));
|
|
break;
|
|
|
|
case VKI_PERF_EVENT_IOC_SET_FILTER:
|
|
PRE_MEM_RASCIIZ("ioctl(VKI_PERF_EVENT_IOC_SET_FILTER).filter", ARG3);
|
|
break;
|
|
|
|
case VKI_PERF_EVENT_IOC_ID:
|
|
PRE_MEM_WRITE("ioctl(VKI_PERF_EVENT_IOC_ID)", (Addr)ARG3, sizeof(__vki_u64));
|
|
break;
|
|
|
|
/* Pulse Per Second (PPS) */
|
|
case VKI_PPS_GETPARAMS: {
|
|
struct vki_pps_kparams *data = (struct vki_pps_kparams *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(PPS_GETPARAMS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PPS_SETPARAMS: {
|
|
struct vki_pps_kparams *data = (struct vki_pps_kparams *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PPS_SETPARAMS).mode", data->mode);
|
|
PRE_FIELD_READ("ioctl(PPS_SETPARAMS).assert_off_tu.sec",
|
|
data->assert_off_tu.sec);
|
|
PRE_FIELD_READ("ioctl(PPS_SETPARAMS).assert_off_tu.nsec",
|
|
data->assert_off_tu.nsec);
|
|
PRE_FIELD_READ("ioctl(PPS_SETPARAMS).clear_off_tu.sec",
|
|
data->clear_off_tu.sec);
|
|
PRE_FIELD_READ("ioctl(PPS_SETPARAMS).clear_off_tu.nsec",
|
|
data->clear_off_tu.nsec);
|
|
break;
|
|
}
|
|
case VKI_PPS_GETCAP:
|
|
PRE_MEM_WRITE("ioctl(PPS_GETCAP)", (Addr)ARG3, sizeof(int));
|
|
break;
|
|
case VKI_PPS_FETCH: {
|
|
struct vki_pps_fdata *data = (struct vki_pps_fdata *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PPS_FETCH).timeout", data->timeout);
|
|
PRE_FIELD_WRITE("ioctl(PPS_FETCH).info", data->info);
|
|
break;
|
|
}
|
|
case VKI_PPS_KC_BIND: {
|
|
struct vki_pps_bind_args *data = (struct vki_pps_bind_args *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(PPS_KC_BIND)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
|
|
/* PTP Hardware Clock */
|
|
case VKI_PTP_CLOCK_GETCAPS: {
|
|
struct vki_ptp_clock_caps *data =
|
|
(struct vki_ptp_clock_caps *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(PTP_CLOCK_GETCAPS)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_EXTTS_REQUEST: {
|
|
struct vki_ptp_extts_request *data =
|
|
(struct vki_ptp_extts_request *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(PTP_EXTTS_REQUEST)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_PEROUT_REQUEST: {
|
|
struct vki_ptp_perout_request *data =
|
|
(struct vki_ptp_perout_request *)(Addr)ARG3;
|
|
PRE_MEM_READ("ioctl(PTP_PEROUT_REQUEST)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_ENABLE_PPS:
|
|
break;
|
|
case VKI_PTP_SYS_OFFSET: {
|
|
struct vki_ptp_sys_offset *data =
|
|
(struct vki_ptp_sys_offset *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PTP_SYS_OFFSET).n_samples", data->n_samples);
|
|
if (data->n_samples <= VKI_PTP_MAX_SAMPLES)
|
|
PRE_MEM_WRITE("ioctl(PTP_SYS_OFFSET).ts", (Addr)data->ts,
|
|
(2 * data->n_samples + 1) * sizeof(data->ts[0]));
|
|
break;
|
|
}
|
|
case VKI_PTP_PIN_GETFUNC: {
|
|
struct vki_ptp_pin_desc *data = (struct vki_ptp_pin_desc *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PTP_PIN_GETFUNC).index", data->index);
|
|
PRE_MEM_WRITE("ioctl(PTP_PIN_GETFUNC)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_PIN_SETFUNC: {
|
|
struct vki_ptp_pin_desc *data = (struct vki_ptp_pin_desc *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PTP_PIN_SETFUNC).index", data->index);
|
|
PRE_FIELD_READ("ioctl(PTP_PIN_SETFUNC).func", data->func);
|
|
PRE_FIELD_READ("ioctl(PTP_PIN_SETFUNC).chan", data->chan);
|
|
break;
|
|
}
|
|
case VKI_PTP_SYS_OFFSET_PRECISE: {
|
|
struct vki_ptp_sys_offset_precise *data =
|
|
(struct vki_ptp_sys_offset_precise *)(Addr)ARG3;
|
|
PRE_MEM_WRITE("ioctl(PTP_SYS_OFFSET_PRECISE)", (Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_SYS_OFFSET_EXTENDED: {
|
|
struct vki_ptp_sys_offset_extended *data =
|
|
(struct vki_ptp_sys_offset_extended *)(Addr)ARG3;
|
|
PRE_FIELD_READ("ioctl(PTP_SYS_OFFSET_EXTENDED).n_samples", data->n_samples);
|
|
PRE_FIELD_READ("ioctl(PTP_SYS_OFFSET_EXTENDED).rsv", data->rsv);
|
|
if (data->n_samples <= VKI_PTP_MAX_SAMPLES)
|
|
PRE_MEM_WRITE("ioctl(PTP_SYS_OFFSET_EXTENDED).ts", (Addr)data->ts,
|
|
3 * data->n_samples * sizeof(data->ts[0][0]));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
/* EVIOC* are variable length and return size written on success */
|
|
switch (ARG2 & ~(_VKI_IOC_SIZEMASK << _VKI_IOC_SIZESHIFT)) {
|
|
case VKI_EVIOCGNAME(0):
|
|
case VKI_EVIOCGPHYS(0):
|
|
case VKI_EVIOCGUNIQ(0):
|
|
case VKI_EVIOCGKEY(0):
|
|
case VKI_EVIOCGLED(0):
|
|
case VKI_EVIOCGSND(0):
|
|
case VKI_EVIOCGSW(0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SYN,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_KEY,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_REL,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_ABS,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_MSC,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SW,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_LED,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SND,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_REP,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_FF,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_PWR,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_FF_STATUS,0):
|
|
PRE_MEM_WRITE("ioctl(EVIO*)", ARG3, _VKI_IOC_SIZE(ARG2));
|
|
break;
|
|
default:
|
|
ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
POST(sys_ioctl)
|
|
{
|
|
ARG2 = (UInt)ARG2;
|
|
|
|
vg_assert(SUCCESS || (FAILURE && VKI_DRM_IOCTL_VERSION == ARG2));
|
|
|
|
/* --- BEGIN special IOCTL handlers for specific Android hardware --- */
|
|
|
|
/* BEGIN undocumented ioctls for PowerVR SGX 540 (the GPU on Nexus S) */
|
|
if (KernelVariantiS(KernelVariant_android_gpu_sgx5xx,
|
|
VG_(clo_kernel_variant))) {
|
|
|
|
if (ARG2 >= 0xC01C6700 && ARG2 <= 0xC01C67FF && ARG3 >= 0x1000) {
|
|
/* What's going on here: there appear to be a bunch of ioctls
|
|
of the form 0xC01C67xx which are undocumented, and if
|
|
unhandled give rise to a vast number of false positives in
|
|
Memcheck.
|
|
|
|
The "normal" interpretation of an ioctl of this form would
|
|
be that the 3rd arg is a pointer to an area of size 0x1C
|
|
(28 bytes) which is filled in by the kernel. Hence you
|
|
might think that "POST_MEM_WRITE(ARG3, 28)" would fix it.
|
|
But it doesn't.
|
|
|
|
It requires POST_MEM_WRITE(ARG3, 256) to silence them.
|
|
One interpretation of this is that ARG3 really does point
|
|
to a 28 byte struct, but inside that are pointers to other
|
|
areas also filled in by the kernel. If these happen to be
|
|
allocated just back up the stack then the 256 byte paint
|
|
might cover them too, somewhat indiscriminately.
|
|
|
|
By printing out ARG3 and also the 28 bytes that it points
|
|
at, it's possible to guess that the 7 word structure has
|
|
this form
|
|
|
|
0 1 2 3 4 5 6
|
|
ioctl-number 0x1C ptr1 ptr1size ptr2 ptr2size aBitMask
|
|
|
|
Unfortunately that doesn't seem to work for some reason,
|
|
so stay with the blunt-instrument approach for the time
|
|
being.
|
|
*/
|
|
if (1) {
|
|
/* blunt-instrument approach */
|
|
POST_MEM_WRITE(ARG3, 256);
|
|
} else {
|
|
/* be a bit more sophisticated */
|
|
POST_MEM_WRITE(ARG3, 28);
|
|
UInt* word = (UInt*)(Addr)ARG3;
|
|
if (word && word[2] && word[3] < 0x200/*stay sane*/)
|
|
POST_MEM_WRITE(word[2], word[3]); // "ptr1"
|
|
if (word && word[4] && word[5] < 0x200/*stay sane*/)
|
|
POST_MEM_WRITE(word[4], word[5]); // "ptr2"
|
|
}
|
|
goto post_sys_ioctl__out;
|
|
}
|
|
}
|
|
/* END undocumented ioctls for PowerVR SGX 540 (the GPU on Nexus S) */
|
|
|
|
/* BEGIN undocumented ioctls for Qualcomm Adreno 3xx */
|
|
if (KernelVariantiS(KernelVariant_android_gpu_adreno3xx,
|
|
VG_(clo_kernel_variant))) {
|
|
if (ARG2 == 0xC00C0902) {
|
|
POST_MEM_WRITE(ARG3, 24); // 16 is not enough
|
|
goto post_sys_ioctl__out;
|
|
}
|
|
}
|
|
/* END undocumented ioctls for Qualcomm Adreno 3xx */
|
|
|
|
/* --- END special IOCTL handlers for specific Android hardware --- */
|
|
|
|
/* --- normal handling --- */
|
|
switch (ARG2 /* request */) {
|
|
|
|
/* The Linux kernel "ion" memory allocator, used on Android. Note:
|
|
this is pretty poor given that there's no pre-handling to check
|
|
that writable areas are addressable. */
|
|
case VKI_ION_IOC_ALLOC: {
|
|
struct vki_ion_allocation_data* data
|
|
= (struct vki_ion_allocation_data*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->handle);
|
|
break;
|
|
}
|
|
case VKI_ION_IOC_MAP: {
|
|
struct vki_ion_fd_data* data = (struct vki_ion_fd_data*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->fd);
|
|
break;
|
|
}
|
|
case VKI_ION_IOC_FREE: // is this necessary?
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_ion_handle_data));
|
|
break;
|
|
case VKI_ION_IOC_SHARE:
|
|
break;
|
|
case VKI_ION_IOC_IMPORT: {
|
|
struct vki_ion_fd_data* data = (struct vki_ion_fd_data*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->handle);
|
|
break;
|
|
}
|
|
case VKI_ION_IOC_SYNC:
|
|
break;
|
|
case VKI_ION_IOC_CUSTOM: // is this necessary?
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_ion_custom_data));
|
|
break;
|
|
|
|
case VKI_SYNC_IOC_MERGE: {
|
|
struct vki_sync_merge_data* data =
|
|
(struct vki_sync_merge_data*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->fence);
|
|
break;
|
|
}
|
|
|
|
case VKI_TCSETS:
|
|
case VKI_TCSETSW:
|
|
case VKI_TCSETSF:
|
|
case VKI_IB_USER_MAD_ENABLE_PKEY:
|
|
break;
|
|
case VKI_TCGETS:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_termios) );
|
|
break;
|
|
case VKI_TCSETA:
|
|
case VKI_TCSETAW:
|
|
case VKI_TCSETAF:
|
|
break;
|
|
case VKI_TCGETA:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_termio) );
|
|
break;
|
|
case VKI_TCSBRK:
|
|
case VKI_TCXONC:
|
|
case VKI_TCSBRKP:
|
|
case VKI_TCFLSH:
|
|
case VKI_TIOCSIG:
|
|
break;
|
|
case VKI_TIOCGWINSZ:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_winsize) );
|
|
break;
|
|
case VKI_TIOCSWINSZ:
|
|
case VKI_TIOCMBIS:
|
|
case VKI_TIOCMBIC:
|
|
case VKI_TIOCMSET:
|
|
break;
|
|
case VKI_TIOCMGET:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TIOCLINUX:
|
|
POST_MEM_WRITE( ARG3, sizeof(char *) );
|
|
break;
|
|
case VKI_TIOCGPGRP:
|
|
/* Get process group ID for foreground processing group. */
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
|
|
break;
|
|
case VKI_TIOCSPGRP:
|
|
/* Set a process group ID? */
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
|
|
break;
|
|
case VKI_TIOCGPTN: /* Get Pty Number (of pty-mux device) */
|
|
POST_MEM_WRITE( ARG3, sizeof(int));
|
|
break;
|
|
case VKI_TIOCSCTTY:
|
|
break;
|
|
case VKI_TIOCSPTLCK: /* Lock/unlock Pty */
|
|
break;
|
|
case VKI_FIONBIO:
|
|
break;
|
|
case VKI_FIONCLEX:
|
|
break;
|
|
case VKI_FIOCLEX:
|
|
break;
|
|
case VKI_TIOCNOTTY:
|
|
break;
|
|
case VKI_FIOASYNC:
|
|
break;
|
|
case VKI_FIONREAD: /* identical to SIOCINQ */
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_FIOQSIZE:
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_loff_t) );
|
|
break;
|
|
|
|
case VKI_TIOCSERGETLSR:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TIOCGICOUNT:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_serial_icounter_struct) );
|
|
break;
|
|
|
|
case VKI_SG_SET_COMMAND_Q:
|
|
break;
|
|
case VKI_SG_IO:
|
|
{
|
|
vki_sg_io_hdr_t *sgio = (vki_sg_io_hdr_t*)(Addr)ARG3;
|
|
if ( sgio->sbp ) {
|
|
POST_MEM_WRITE( (Addr)sgio->sbp, sgio->sb_len_wr );
|
|
}
|
|
if ( sgio->dxfer_direction == VKI_SG_DXFER_FROM_DEV ||
|
|
sgio->dxfer_direction == VKI_SG_DXFER_TO_FROM_DEV ) {
|
|
int transferred = sgio->dxfer_len - sgio->resid;
|
|
POST_MEM_WRITE( (Addr)sgio->dxferp, transferred );
|
|
}
|
|
}
|
|
break;
|
|
case VKI_SG_GET_SCSI_ID:
|
|
POST_MEM_WRITE(ARG3, sizeof(vki_sg_scsi_id_t));
|
|
break;
|
|
case VKI_SG_SET_RESERVED_SIZE:
|
|
break;
|
|
case VKI_SG_SET_TIMEOUT:
|
|
break;
|
|
case VKI_SG_GET_RESERVED_SIZE:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SG_GET_TIMEOUT:
|
|
break;
|
|
case VKI_SG_GET_VERSION_NUM:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SG_EMULATED_HOST:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SG_GET_SG_TABLESIZE:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
|
|
case VKI_IIOCGETCPS:
|
|
POST_MEM_WRITE( ARG3, VKI_ISDN_MAX_CHANNELS * 2 * sizeof(unsigned long) );
|
|
break;
|
|
case VKI_IIOCNETGPN:
|
|
POST_MEM_WRITE( ARG3, sizeof(vki_isdn_net_ioctl_phone) );
|
|
break;
|
|
|
|
/* These all use struct ifreq AFAIK */
|
|
case VKI_SIOCGIFINDEX: /* get iface index */
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_ifindex,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_ifindex));
|
|
break;
|
|
case VKI_SIOCGIFFLAGS: /* get flags */
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags));
|
|
break;
|
|
case VKI_SIOCGIFHWADDR: /* Get hardware address */
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_hwaddr,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_hwaddr));
|
|
break;
|
|
case VKI_SIOCGIFMTU: /* get MTU size */
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_mtu,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_mtu) );
|
|
break;
|
|
case VKI_SIOCGIFADDR: /* get PA address */
|
|
case VKI_SIOCGIFDSTADDR: /* get remote PA address */
|
|
case VKI_SIOCGIFBRDADDR: /* get broadcast PA address */
|
|
case VKI_SIOCGIFNETMASK: /* get network PA mask */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_addr,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_addr) );
|
|
break;
|
|
case VKI_SIOCGIFMETRIC: /* get metric */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_metric,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_metric) );
|
|
break;
|
|
case VKI_SIOCGIFMAP: /* Get device parameters */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_map,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_map) );
|
|
break;
|
|
break;
|
|
case VKI_SIOCGIFTXQLEN: /* Get the tx queue length */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_qlen,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_qlen) );
|
|
break;
|
|
case VKI_SIOCGIFNAME: /* get iface name */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name) );
|
|
break;
|
|
case VKI_SIOCETHTOOL: { /* ethtool(8) interface */
|
|
struct vki_ifreq *ir = (struct vki_ifreq *)(Addr)ARG3;
|
|
switch ( *(vki_u32 *)ir->vki_ifr_data ) {
|
|
case VKI_ETHTOOL_GSET:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_cmd));
|
|
break;
|
|
case VKI_ETHTOOL_SSET:
|
|
break;
|
|
case VKI_ETHTOOL_GDRVINFO:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_drvinfo) );
|
|
break;
|
|
case VKI_ETHTOOL_GREGS:
|
|
POST_MEM_WRITE( (Addr)((struct vki_ethtool_regs *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_regs *)ir->vki_ifr_data)->len );
|
|
break;
|
|
case VKI_ETHTOOL_GWOL:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_wolinfo) );
|
|
break;
|
|
case VKI_ETHTOOL_SWOL:
|
|
break;
|
|
case VKI_ETHTOOL_GMSGLVL:
|
|
case VKI_ETHTOOL_GLINK:
|
|
case VKI_ETHTOOL_GRXCSUM:
|
|
case VKI_ETHTOOL_GSG:
|
|
case VKI_ETHTOOL_GTSO:
|
|
case VKI_ETHTOOL_GUFO:
|
|
case VKI_ETHTOOL_GGSO:
|
|
case VKI_ETHTOOL_GFLAGS:
|
|
case VKI_ETHTOOL_GGRO:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_value));
|
|
break;
|
|
case VKI_ETHTOOL_SMSGLVL:
|
|
case VKI_ETHTOOL_SRXCSUM:
|
|
case VKI_ETHTOOL_SSG:
|
|
case VKI_ETHTOOL_STSO:
|
|
case VKI_ETHTOOL_SUFO:
|
|
case VKI_ETHTOOL_SGSO:
|
|
case VKI_ETHTOOL_SFLAGS:
|
|
case VKI_ETHTOOL_SGRO:
|
|
break;
|
|
case VKI_ETHTOOL_NWAY_RST:
|
|
break;
|
|
case VKI_ETHTOOL_GRINGPARAM:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_ringparam));
|
|
break;
|
|
case VKI_ETHTOOL_SRINGPARAM:
|
|
break;
|
|
case VKI_ETHTOOL_TEST:
|
|
POST_MEM_WRITE( (Addr)((struct vki_ethtool_test *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_test *)ir->vki_ifr_data)->len * sizeof(__vki_u64) );
|
|
break;
|
|
case VKI_ETHTOOL_PHYS_ID:
|
|
break;
|
|
case VKI_ETHTOOL_GPERMADDR:
|
|
POST_MEM_WRITE( (Addr)((struct vki_ethtool_perm_addr *)ir->vki_ifr_data)->data,
|
|
((struct vki_ethtool_perm_addr *)ir->vki_ifr_data)->size );
|
|
break;
|
|
case VKI_ETHTOOL_RESET:
|
|
break;
|
|
case VKI_ETHTOOL_GSSET_INFO:
|
|
POST_MEM_WRITE( (Addr)((struct vki_ethtool_sset_info *)ir->vki_ifr_data)->data,
|
|
__builtin_popcountll(((struct vki_ethtool_sset_info *)ir->vki_ifr_data)->sset_mask) * sizeof(__vki_u32) );
|
|
break;
|
|
case VKI_ETHTOOL_GFEATURES:
|
|
POST_MEM_WRITE( (Addr)((struct vki_ethtool_gfeatures *)ir->vki_ifr_data)->features,
|
|
((struct vki_ethtool_gfeatures *)ir->vki_ifr_data)->size * sizeof(struct vki_ethtool_get_features_block) );
|
|
break;
|
|
case VKI_ETHTOOL_SFEATURES:
|
|
break;
|
|
case VKI_ETHTOOL_GCHANNELS:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_channels) );
|
|
break;
|
|
case VKI_ETHTOOL_SCHANNELS:
|
|
break;
|
|
case VKI_ETHTOOL_GET_TS_INFO:
|
|
POST_MEM_WRITE( (Addr)ir->vki_ifr_data, sizeof(struct vki_ethtool_ts_info) );
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_SIOCGMIIPHY: /* get hardware entry */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->phy_id));
|
|
break;
|
|
case VKI_SIOCGMIIREG: /* get hardware entry registers */
|
|
POST_MEM_WRITE(
|
|
(Addr)&((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->val_out,
|
|
sizeof(((struct vki_mii_ioctl_data *)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_data)->val_out));
|
|
break;
|
|
|
|
/* tun/tap related ioctls */
|
|
case VKI_TUNSETIFF:
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name) );
|
|
break;
|
|
case VKI_TUNGETFEATURES:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_TUNGETIFF:
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_name) );
|
|
POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags,
|
|
sizeof(((struct vki_ifreq *)(Addr)ARG3)->vki_ifr_flags) );
|
|
break;
|
|
case VKI_TUNGETSNDBUF:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_TUNGETVNETHDRSZ:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
|
|
case VKI_SIOCGIFCONF: /* get iface list */
|
|
/* WAS:
|
|
PRE_MEM_WRITE("ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
|
|
KERNEL_DO_SYSCALL(tid,RES);
|
|
if (!VG_(is_kerror)(RES) && RES == 0)
|
|
POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
|
|
*/
|
|
if (RES == 0 && ARG3 ) {
|
|
struct vki_ifconf *ifc = (struct vki_ifconf *) (Addr)ARG3;
|
|
if (ifc->vki_ifc_buf != NULL)
|
|
POST_MEM_WRITE( (Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
|
|
}
|
|
break;
|
|
case VKI_SIOCGSTAMP:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_timeval) );
|
|
break;
|
|
case VKI_SIOCGSTAMPNS:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_timespec) );
|
|
break;
|
|
/* SIOCOUTQ is an ioctl that, when called on a socket, returns
|
|
the number of bytes currently in that socket's send buffer.
|
|
It writes this value as an int to the memory location
|
|
indicated by the third argument of ioctl(2). */
|
|
case VKI_SIOCOUTQ:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SIOCGRARP: /* get RARP table entry */
|
|
case VKI_SIOCGARP: /* get ARP table entry */
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_arpreq));
|
|
break;
|
|
|
|
case VKI_SIOCSIFFLAGS: /* set flags */
|
|
case VKI_SIOCSIFMAP: /* Set device parameters */
|
|
case VKI_SIOCSHWTSTAMP: /* Set hardware time stamping */
|
|
case VKI_SIOCSIFTXQLEN: /* Set the tx queue length */
|
|
case VKI_SIOCSIFDSTADDR: /* set remote PA address */
|
|
case VKI_SIOCSIFBRDADDR: /* set broadcast PA address */
|
|
case VKI_SIOCSIFNETMASK: /* set network PA mask */
|
|
case VKI_SIOCSIFMETRIC: /* set metric */
|
|
case VKI_SIOCSIFADDR: /* set PA address */
|
|
case VKI_SIOCSIFMTU: /* set MTU size */
|
|
case VKI_SIOCSIFHWADDR: /* set hardware address */
|
|
case VKI_SIOCSMIIREG: /* set hardware entry registers */
|
|
break;
|
|
/* Routing table calls. */
|
|
case VKI_SIOCADDRT: /* add routing table entry */
|
|
case VKI_SIOCDELRT: /* delete routing table entry */
|
|
break;
|
|
|
|
/* RARP cache control calls. */
|
|
case VKI_SIOCDRARP: /* delete RARP table entry */
|
|
case VKI_SIOCSRARP: /* set RARP table entry */
|
|
/* ARP cache control calls. */
|
|
case VKI_SIOCSARP: /* set ARP table entry */
|
|
case VKI_SIOCDARP: /* delete ARP table entry */
|
|
break;
|
|
|
|
case VKI_SIOCGPGRP:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SIOCSPGRP:
|
|
break;
|
|
|
|
case VKI_SIOCATMARK:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
|
|
/* linux/soundcard interface (OSS) */
|
|
case VKI_SNDCTL_SEQ_GETOUTCOUNT:
|
|
case VKI_SNDCTL_SEQ_GETINCOUNT:
|
|
case VKI_SNDCTL_SEQ_PERCMODE:
|
|
case VKI_SNDCTL_SEQ_TESTMIDI:
|
|
case VKI_SNDCTL_SEQ_RESETSAMPLES:
|
|
case VKI_SNDCTL_SEQ_NRSYNTHS:
|
|
case VKI_SNDCTL_SEQ_NRMIDIS:
|
|
case VKI_SNDCTL_SEQ_GETTIME:
|
|
case VKI_SNDCTL_DSP_GETBLKSIZE:
|
|
case VKI_SNDCTL_DSP_GETFMTS:
|
|
case VKI_SNDCTL_DSP_SETFMT:
|
|
case VKI_SNDCTL_DSP_GETTRIGGER:
|
|
case VKI_SNDCTL_DSP_GETODELAY:
|
|
case VKI_SNDCTL_DSP_GETSPDIF:
|
|
case VKI_SNDCTL_DSP_GETCAPS:
|
|
case VKI_SOUND_PCM_READ_RATE:
|
|
case VKI_SOUND_PCM_READ_CHANNELS:
|
|
case VKI_SOUND_PCM_READ_BITS:
|
|
case VKI_SOUND_PCM_READ_FILTER:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_SNDCTL_SEQ_CTRLRATE:
|
|
case VKI_SNDCTL_DSP_SPEED:
|
|
case VKI_SNDCTL_DSP_STEREO:
|
|
case VKI_SNDCTL_DSP_CHANNELS:
|
|
case VKI_SOUND_PCM_WRITE_FILTER:
|
|
case VKI_SNDCTL_DSP_SUBDIVIDE:
|
|
case VKI_SNDCTL_DSP_SETFRAGMENT:
|
|
case VKI_SNDCTL_DSP_GETCHANNELMASK:
|
|
case VKI_SNDCTL_DSP_BIND_CHANNEL:
|
|
case VKI_SNDCTL_TMR_TIMEBASE:
|
|
case VKI_SNDCTL_TMR_TEMPO:
|
|
case VKI_SNDCTL_TMR_SOURCE:
|
|
case VKI_SNDCTL_MIDI_PRETIME:
|
|
case VKI_SNDCTL_MIDI_MPUMODE:
|
|
break;
|
|
case VKI_SNDCTL_DSP_GETOSPACE:
|
|
case VKI_SNDCTL_DSP_GETISPACE:
|
|
POST_MEM_WRITE(ARG3, sizeof(vki_audio_buf_info));
|
|
break;
|
|
case VKI_SNDCTL_DSP_NONBLOCK:
|
|
break;
|
|
case VKI_SNDCTL_DSP_SETTRIGGER:
|
|
break;
|
|
|
|
case VKI_SNDCTL_DSP_POST:
|
|
case VKI_SNDCTL_DSP_RESET:
|
|
case VKI_SNDCTL_DSP_SYNC:
|
|
case VKI_SNDCTL_DSP_SETSYNCRO:
|
|
case VKI_SNDCTL_DSP_SETDUPLEX:
|
|
break;
|
|
|
|
/* linux/soundcard interface (ALSA) */
|
|
case VKI_SNDRV_PCM_IOCTL_HW_FREE:
|
|
case VKI_SNDRV_PCM_IOCTL_HWSYNC:
|
|
case VKI_SNDRV_PCM_IOCTL_PREPARE:
|
|
case VKI_SNDRV_PCM_IOCTL_RESET:
|
|
case VKI_SNDRV_PCM_IOCTL_START:
|
|
case VKI_SNDRV_PCM_IOCTL_DROP:
|
|
case VKI_SNDRV_PCM_IOCTL_DRAIN:
|
|
case VKI_SNDRV_PCM_IOCTL_RESUME:
|
|
case VKI_SNDRV_PCM_IOCTL_XRUN:
|
|
case VKI_SNDRV_PCM_IOCTL_UNLINK:
|
|
case VKI_SNDRV_TIMER_IOCTL_START:
|
|
case VKI_SNDRV_TIMER_IOCTL_STOP:
|
|
case VKI_SNDRV_TIMER_IOCTL_CONTINUE:
|
|
case VKI_SNDRV_TIMER_IOCTL_PAUSE:
|
|
break;
|
|
|
|
case VKI_SNDRV_CTL_IOCTL_PVERSION: {
|
|
POST_MEM_WRITE( (Addr)ARG3, sizeof(int) );
|
|
break;
|
|
}
|
|
case VKI_SNDRV_CTL_IOCTL_CARD_INFO:
|
|
POST_MEM_WRITE( (Addr)ARG3, sizeof(struct vki_snd_ctl_card_info) );
|
|
break;
|
|
case VKI_SNDRV_CTL_IOCTL_ELEM_LIST: {
|
|
struct vki_snd_ctl_elem_list *data =
|
|
(struct vki_snd_ctl_elem_list *)(Addr)ARG3;
|
|
POST_MEM_WRITE( (Addr)&data->used, sizeof(data->used) );
|
|
POST_MEM_WRITE( (Addr)&data->count, sizeof(data->count) );
|
|
if (data->pids) {
|
|
POST_MEM_WRITE( (Addr)data->pids, sizeof(struct vki_snd_ctl_elem_id) * data->used );
|
|
}
|
|
break;
|
|
}
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_READ: {
|
|
struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)(Addr)ARG3;
|
|
POST_MEM_WRITE( (Addr)data->tlv, data->length );
|
|
break;
|
|
}
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_WRITE:
|
|
case VKI_SNDRV_CTL_IOCTL_TLV_COMMAND:
|
|
break;
|
|
|
|
/* SCSI no operand */
|
|
case VKI_SCSI_IOCTL_DOORLOCK:
|
|
case VKI_SCSI_IOCTL_DOORUNLOCK:
|
|
break;
|
|
|
|
/* Real Time Clock (/dev/rtc) ioctls */
|
|
case VKI_RTC_UIE_ON:
|
|
case VKI_RTC_UIE_OFF:
|
|
case VKI_RTC_AIE_ON:
|
|
case VKI_RTC_AIE_OFF:
|
|
case VKI_RTC_PIE_ON:
|
|
case VKI_RTC_PIE_OFF:
|
|
case VKI_RTC_IRQP_SET:
|
|
break;
|
|
case VKI_RTC_RD_TIME:
|
|
case VKI_RTC_ALM_READ:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_rtc_time));
|
|
break;
|
|
case VKI_RTC_ALM_SET:
|
|
break;
|
|
case VKI_RTC_IRQP_READ:
|
|
POST_MEM_WRITE(ARG3, sizeof(unsigned long));
|
|
break;
|
|
|
|
/* Loopback devices */
|
|
case VKI_LOOP_CTL_ADD:
|
|
case VKI_LOOP_CTL_REMOVE:
|
|
case VKI_LOOP_CTL_GET_FREE:
|
|
break;
|
|
/* Loopback device */
|
|
case VKI_LOOP_SET_FD:
|
|
case VKI_LOOP_CLR_FD:
|
|
case VKI_LOOP_CHANGE_FD:
|
|
case VKI_LOOP_SET_CAPACITY:
|
|
case VKI_LOOP_SET_DIRECT_IO:
|
|
case VKI_LOOP_SET_BLOCK_SIZE:
|
|
break;
|
|
case VKI_LOOP_SET_STATUS:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_loop_info));
|
|
break;
|
|
case VKI_LOOP_GET_STATUS:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_loop_info));
|
|
break;
|
|
case VKI_LOOP_SET_STATUS64:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_loop_info64));
|
|
break;
|
|
case VKI_LOOP_GET_STATUS64:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_loop_info64));
|
|
break;
|
|
|
|
|
|
/* Block devices */
|
|
case VKI_BLKROSET:
|
|
break;
|
|
case VKI_BLKROGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKGETSIZE:
|
|
POST_MEM_WRITE(ARG3, sizeof(unsigned long));
|
|
break;
|
|
case VKI_BLKFLSBUF:
|
|
break;
|
|
case VKI_BLKRASET:
|
|
break;
|
|
case VKI_BLKRAGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(long));
|
|
break;
|
|
case VKI_BLKFRASET:
|
|
break;
|
|
case VKI_BLKFRAGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(long));
|
|
break;
|
|
case VKI_BLKSECTGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(unsigned short));
|
|
break;
|
|
case VKI_BLKSSZGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKBSZGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKBSZSET:
|
|
break;
|
|
case VKI_BLKGETSIZE64:
|
|
POST_MEM_WRITE(ARG3, sizeof(unsigned long long));
|
|
break;
|
|
case VKI_BLKPBSZGET:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKIOMIN:
|
|
POST_MEM_WRITE(ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKIOOPT:
|
|
POST_MEM_WRITE(ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKALIGNOFF:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_BLKDISCARDZEROES:
|
|
POST_MEM_WRITE(ARG3, sizeof(vki_uint));
|
|
break;
|
|
case VKI_BLKREPORTZONE: {
|
|
const struct vki_blk_zone_report *zr = (void *)(Addr)ARG3;
|
|
|
|
POST_MEM_WRITE(ARG3, sizeof(*zr) + zr->nr_zones * sizeof(zr->zones[0]));
|
|
break;
|
|
}
|
|
case VKI_BLKRESETZONE:
|
|
break;
|
|
|
|
/* Hard disks */
|
|
case VKI_HDIO_GETGEO: /* 0x0301 */
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_hd_geometry));
|
|
break;
|
|
case VKI_HDIO_GET_DMA: /* 0x030b */
|
|
POST_MEM_WRITE(ARG3, sizeof(long));
|
|
break;
|
|
case VKI_HDIO_GET_IDENTITY: /* 0x030d */
|
|
POST_MEM_WRITE(ARG3, VKI_SIZEOF_STRUCT_HD_DRIVEID );
|
|
break;
|
|
|
|
/* SCSI */
|
|
case VKI_SCSI_IOCTL_GET_IDLUN: /* 0x5382 */
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_scsi_idlun));
|
|
break;
|
|
case VKI_SCSI_IOCTL_GET_BUS_NUMBER: /* 0x5386 */
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
|
|
/* CD ROM stuff (??) */
|
|
case VKI_CDROM_DISC_STATUS:
|
|
case VKI_CDROMSTOP:
|
|
break;
|
|
case VKI_CDROMSUBCHNL:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_cdrom_subchnl));
|
|
break;
|
|
case VKI_CDROMREADTOCHDR:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_cdrom_tochdr));
|
|
break;
|
|
case VKI_CDROMREADTOCENTRY:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_cdrom_tocentry));
|
|
break;
|
|
case VKI_CDROMMULTISESSION:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_cdrom_multisession));
|
|
break;
|
|
case VKI_CDROMVOLREAD:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_cdrom_volctrl));
|
|
break;
|
|
case VKI_CDROMREADMODE1:
|
|
POST_MEM_WRITE(ARG3, VKI_CD_FRAMESIZE_RAW1);
|
|
break;
|
|
case VKI_CDROMREADMODE2:
|
|
POST_MEM_WRITE(ARG3, VKI_CD_FRAMESIZE_RAW0);
|
|
break;
|
|
case VKI_CDROMREADRAW:
|
|
POST_MEM_WRITE(ARG3, VKI_CD_FRAMESIZE_RAW);
|
|
break;
|
|
case VKI_CDROMREADAUDIO:
|
|
{
|
|
struct vki_cdrom_read_audio *cra =
|
|
(struct vki_cdrom_read_audio *) (Addr)ARG3;
|
|
POST_MEM_WRITE( (Addr)(cra->buf), cra->nframes * VKI_CD_FRAMESIZE_RAW);
|
|
break;
|
|
}
|
|
|
|
case VKI_CDROMPLAYMSF:
|
|
break;
|
|
/* The following two are probably bogus (should check args
|
|
for readability). JRS 20021117 */
|
|
case VKI_CDROM_DRIVE_STATUS: /* 0x5326 */
|
|
case VKI_CDROM_CLEAR_OPTIONS: /* 0x5321 */
|
|
break;
|
|
case VKI_CDROM_GET_CAPABILITY: /* 0x5331 */
|
|
break;
|
|
|
|
/* DVD stuff */
|
|
case VKI_DVD_READ_STRUCT:
|
|
break;
|
|
|
|
case VKI_FIGETBSZ:
|
|
POST_MEM_WRITE(ARG3, sizeof(unsigned long));
|
|
break;
|
|
case VKI_FIBMAP:
|
|
POST_MEM_WRITE(ARG3, sizeof(int));
|
|
break;
|
|
case VKI_FICLONE:
|
|
break;
|
|
|
|
case VKI_FBIOGET_VSCREENINFO: //0x4600
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_fb_var_screeninfo));
|
|
break;
|
|
case VKI_FBIOGET_FSCREENINFO: //0x4602
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_fb_fix_screeninfo));
|
|
break;
|
|
|
|
case VKI_PPCLAIM:
|
|
case VKI_PPEXCL:
|
|
case VKI_PPYIELD:
|
|
case VKI_PPRELEASE:
|
|
case VKI_PPSETMODE:
|
|
case VKI_PPSETPHASE:
|
|
case VKI_PPSETFLAGS:
|
|
case VKI_PPWDATA:
|
|
case VKI_PPWCONTROL:
|
|
case VKI_PPFCONTROL:
|
|
case VKI_PPDATADIR:
|
|
case VKI_PPNEGOT:
|
|
case VKI_PPWCTLONIRQ:
|
|
case VKI_PPSETTIME:
|
|
break;
|
|
case VKI_PPGETMODE:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETPHASE:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETMODES:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned int) );
|
|
break;
|
|
case VKI_PPGETFLAGS:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPRSTATUS:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPRDATA:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPRCONTROL:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned char) );
|
|
break;
|
|
case VKI_PPCLRIRQ:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_PPGETTIME:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_timeval) );
|
|
break;
|
|
|
|
case VKI_GIO_FONT:
|
|
POST_MEM_WRITE( ARG3, 32 * 256 );
|
|
break;
|
|
case VKI_PIO_FONT:
|
|
break;
|
|
|
|
case VKI_GIO_FONTX:
|
|
POST_MEM_WRITE((Addr)((struct vki_consolefontdesc *)(Addr)ARG3)->chardata,
|
|
32 * ((struct vki_consolefontdesc *)(Addr)ARG3)->charcount);
|
|
break;
|
|
case VKI_PIO_FONTX:
|
|
break;
|
|
|
|
case VKI_PIO_FONTRESET:
|
|
break;
|
|
|
|
case VKI_GIO_CMAP:
|
|
POST_MEM_WRITE( ARG3, 16 * 3 );
|
|
break;
|
|
case VKI_PIO_CMAP:
|
|
break;
|
|
|
|
case VKI_KIOCSOUND:
|
|
case VKI_KDMKTONE:
|
|
break;
|
|
|
|
case VKI_KDGETLED:
|
|
POST_MEM_WRITE( ARG3, sizeof(char) );
|
|
break;
|
|
case VKI_KDSETLED:
|
|
break;
|
|
|
|
case VKI_KDGKBTYPE:
|
|
POST_MEM_WRITE( ARG3, sizeof(char) );
|
|
break;
|
|
|
|
case VKI_KDADDIO:
|
|
case VKI_KDDELIO:
|
|
case VKI_KDENABIO:
|
|
case VKI_KDDISABIO:
|
|
break;
|
|
|
|
case VKI_KDSETMODE:
|
|
break;
|
|
case VKI_KDGETMODE:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
|
|
case VKI_KDMAPDISP:
|
|
case VKI_KDUNMAPDISP:
|
|
break;
|
|
|
|
case VKI_GIO_SCRNMAP:
|
|
POST_MEM_WRITE( ARG3, VKI_E_TABSZ );
|
|
break;
|
|
case VKI_PIO_SCRNMAP:
|
|
break;
|
|
case VKI_GIO_UNISCRNMAP:
|
|
POST_MEM_WRITE( ARG3, VKI_E_TABSZ * sizeof(unsigned short) );
|
|
break;
|
|
case VKI_PIO_UNISCRNMAP:
|
|
break;
|
|
|
|
case VKI_GIO_UNIMAP:
|
|
if ( ARG3 ) {
|
|
struct vki_unimapdesc *desc = (struct vki_unimapdesc *) (Addr)ARG3;
|
|
POST_MEM_WRITE( (Addr)&desc->entry_ct, sizeof(desc->entry_ct));
|
|
POST_MEM_WRITE( (Addr)desc->entries,
|
|
desc->entry_ct * sizeof(struct vki_unipair) );
|
|
}
|
|
break;
|
|
case VKI_PIO_UNIMAP:
|
|
break;
|
|
case VKI_PIO_UNIMAPCLR:
|
|
break;
|
|
|
|
case VKI_KDGKBMODE:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_KDSKBMODE:
|
|
break;
|
|
|
|
case VKI_KDGKBMETA:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_KDSKBMETA:
|
|
break;
|
|
|
|
case VKI_KDGKBLED:
|
|
POST_MEM_WRITE( ARG3, sizeof(char) );
|
|
break;
|
|
case VKI_KDSKBLED:
|
|
break;
|
|
|
|
case VKI_KDGKBENT:
|
|
POST_MEM_WRITE( (Addr)&((struct vki_kbentry *)(Addr)ARG3)->kb_value,
|
|
sizeof(((struct vki_kbentry *)(Addr)ARG3)->kb_value) );
|
|
break;
|
|
case VKI_KDSKBENT:
|
|
break;
|
|
|
|
case VKI_KDGKBSENT:
|
|
POST_MEM_WRITE( (Addr)((struct vki_kbsentry *)(Addr)ARG3)->kb_string,
|
|
sizeof(((struct vki_kbsentry *)(Addr)ARG3)->kb_string) );
|
|
break;
|
|
case VKI_KDSKBSENT:
|
|
break;
|
|
|
|
case VKI_KDGKBDIACR:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_kbdiacrs) );
|
|
break;
|
|
case VKI_KDSKBDIACR:
|
|
break;
|
|
|
|
case VKI_KDGETKEYCODE:
|
|
POST_MEM_WRITE( (Addr)((struct vki_kbkeycode *)(Addr)ARG3)->keycode,
|
|
sizeof(((struct vki_kbkeycode *)(Addr)ARG3)->keycode) );
|
|
break;
|
|
case VKI_KDSETKEYCODE:
|
|
break;
|
|
|
|
case VKI_KDSIGACCEPT:
|
|
break;
|
|
|
|
case VKI_KDKBDREP:
|
|
break;
|
|
|
|
case VKI_KDFONTOP:
|
|
if ( ARG3 ) {
|
|
struct vki_console_font_op *op =
|
|
(struct vki_console_font_op *) (Addr)ARG3;
|
|
switch ( op->op ) {
|
|
case VKI_KD_FONT_OP_SET:
|
|
break;
|
|
case VKI_KD_FONT_OP_GET:
|
|
if ( op->data )
|
|
POST_MEM_WRITE( (Addr) op->data,
|
|
(op->width + 7) / 8 * 32 * op->charcount );
|
|
break;
|
|
case VKI_KD_FONT_OP_SET_DEFAULT:
|
|
break;
|
|
case VKI_KD_FONT_OP_COPY:
|
|
break;
|
|
}
|
|
POST_MEM_WRITE( (Addr) op, sizeof(*op));
|
|
}
|
|
break;
|
|
|
|
case VKI_VT_OPENQRY:
|
|
POST_MEM_WRITE( ARG3, sizeof(int) );
|
|
break;
|
|
case VKI_VT_GETMODE:
|
|
POST_MEM_WRITE( ARG3, sizeof(struct vki_vt_mode) );
|
|
break;
|
|
case VKI_VT_SETMODE:
|
|
break;
|
|
case VKI_VT_GETSTATE:
|
|
POST_MEM_WRITE( (Addr) &(((struct vki_vt_stat*) (Addr)ARG3)->v_active),
|
|
sizeof(((struct vki_vt_stat*) (Addr)ARG3)->v_active) );
|
|
POST_MEM_WRITE( (Addr) &(((struct vki_vt_stat*) (Addr)ARG3)->v_state),
|
|
sizeof(((struct vki_vt_stat*) (Addr)ARG3)->v_state) );
|
|
break;
|
|
case VKI_VT_RELDISP:
|
|
case VKI_VT_ACTIVATE:
|
|
case VKI_VT_WAITACTIVE:
|
|
case VKI_VT_DISALLOCATE:
|
|
break;
|
|
case VKI_VT_RESIZE:
|
|
break;
|
|
case VKI_VT_RESIZEX:
|
|
break;
|
|
case VKI_VT_LOCKSWITCH:
|
|
case VKI_VT_UNLOCKSWITCH:
|
|
break;
|
|
|
|
case VKI_USBDEVFS_CONTROL:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_ctrltransfer *vkuc =
|
|
(struct vki_usbdevfs_ctrltransfer *)(Addr)ARG3;
|
|
if (vkuc->bRequestType & 0x80)
|
|
POST_MEM_WRITE((Addr)vkuc->data, RES);
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_BULK:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_bulktransfer *vkub =
|
|
(struct vki_usbdevfs_bulktransfer *)(Addr)ARG3;
|
|
if (vkub->ep & 0x80)
|
|
POST_MEM_WRITE((Addr)vkub->data, RES);
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_GETDRIVER:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_getdriver *vkugd =
|
|
(struct vki_usbdevfs_getdriver *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&vkugd->driver, sizeof(vkugd->driver));
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_REAPURB:
|
|
case VKI_USBDEVFS_REAPURBNDELAY:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_urb **vkuu = (struct vki_usbdevfs_urb**)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)vkuu, sizeof(*vkuu));
|
|
if (!*vkuu)
|
|
break;
|
|
POST_MEM_WRITE((Addr) &((*vkuu)->status),sizeof((*vkuu)->status));
|
|
if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
|
|
struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)(*vkuu)->buffer;
|
|
if (vkusp->bRequestType & 0x80)
|
|
POST_MEM_WRITE((Addr)(vkusp+1), (*vkuu)->buffer_length - sizeof(*vkusp));
|
|
POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
|
|
} else if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_ISO) {
|
|
char *bp = (*vkuu)->buffer;
|
|
int i;
|
|
for(i=0; i<(*vkuu)->number_of_packets; i++) {
|
|
POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].actual_length, sizeof((*vkuu)->iso_frame_desc[i].actual_length));
|
|
POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].status, sizeof((*vkuu)->iso_frame_desc[i].status));
|
|
if ((*vkuu)->endpoint & 0x80)
|
|
POST_MEM_WRITE((Addr)bp, (*vkuu)->iso_frame_desc[i].actual_length);
|
|
bp += (*vkuu)->iso_frame_desc[i].length; // FIXME: or actual_length??
|
|
}
|
|
POST_MEM_WRITE((Addr)&(*vkuu)->error_count, sizeof((*vkuu)->error_count));
|
|
} else {
|
|
if ((*vkuu)->endpoint & 0x80)
|
|
POST_MEM_WRITE((Addr)(*vkuu)->buffer, (*vkuu)->actual_length);
|
|
POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
|
|
}
|
|
}
|
|
break;
|
|
case VKI_USBDEVFS_CONNECTINFO:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_usbdevfs_connectinfo));
|
|
break;
|
|
case VKI_USBDEVFS_IOCTL:
|
|
if ( ARG3 ) {
|
|
struct vki_usbdevfs_ioctl *vkui =
|
|
(struct vki_usbdevfs_ioctl *)(Addr)ARG3;
|
|
UInt dir2, size2;
|
|
dir2 = _VKI_IOC_DIR(vkui->ioctl_code);
|
|
size2 = _VKI_IOC_SIZE(vkui->ioctl_code);
|
|
if (size2 > 0) {
|
|
if (dir2 & _VKI_IOC_READ)
|
|
POST_MEM_WRITE((Addr)vkui->data, size2);
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* I2C (/dev/i2c-*) ioctls */
|
|
case VKI_I2C_SLAVE:
|
|
case VKI_I2C_SLAVE_FORCE:
|
|
case VKI_I2C_TENBIT:
|
|
case VKI_I2C_PEC:
|
|
break;
|
|
case VKI_I2C_FUNCS:
|
|
POST_MEM_WRITE( ARG3, sizeof(unsigned long) );
|
|
break;
|
|
case VKI_I2C_RDWR:
|
|
if ( ARG3 ) {
|
|
struct vki_i2c_rdwr_ioctl_data *vkui =
|
|
(struct vki_i2c_rdwr_ioctl_data *)(Addr)ARG3;
|
|
UInt i;
|
|
for (i=0; i < vkui->nmsgs; i++) {
|
|
struct vki_i2c_msg *msg = vkui->msgs + i;
|
|
if (msg->flags & VKI_I2C_M_RD)
|
|
POST_MEM_WRITE((Addr)msg->buf, msg->len);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_I2C_SMBUS:
|
|
if ( ARG3 ) {
|
|
struct vki_i2c_smbus_ioctl_data *vkis
|
|
= (struct vki_i2c_smbus_ioctl_data *) (Addr)ARG3;
|
|
/* i2c_smbus_write_quick hides its value in read_write, so
|
|
this variable can have a different meaning */
|
|
if ((vkis->read_write == VKI_I2C_SMBUS_READ)
|
|
|| (vkis->size == VKI_I2C_SMBUS_PROC_CALL)
|
|
|| (vkis->size == VKI_I2C_SMBUS_BLOCK_PROC_CALL)) {
|
|
if ( ! (vkis->size == VKI_I2C_SMBUS_QUICK)) {
|
|
UInt size;
|
|
switch(vkis->size) {
|
|
case VKI_I2C_SMBUS_BYTE:
|
|
case VKI_I2C_SMBUS_BYTE_DATA:
|
|
size = 1;
|
|
break;
|
|
case VKI_I2C_SMBUS_WORD_DATA:
|
|
case VKI_I2C_SMBUS_PROC_CALL:
|
|
size = 2;
|
|
break;
|
|
case VKI_I2C_SMBUS_BLOCK_DATA:
|
|
case VKI_I2C_SMBUS_I2C_BLOCK_BROKEN:
|
|
case VKI_I2C_SMBUS_BLOCK_PROC_CALL:
|
|
case VKI_I2C_SMBUS_I2C_BLOCK_DATA:
|
|
size = 1 + vkis->data->block[0];
|
|
break;
|
|
default:
|
|
size = 0;
|
|
}
|
|
POST_MEM_WRITE((Addr)&vkis->data->block[0], size);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Wireless extensions ioctls */
|
|
case VKI_SIOCSIWCOMMIT:
|
|
case VKI_SIOCSIWNWID:
|
|
case VKI_SIOCSIWFREQ:
|
|
case VKI_SIOCSIWMODE:
|
|
case VKI_SIOCSIWSENS:
|
|
case VKI_SIOCSIWRANGE:
|
|
case VKI_SIOCSIWPRIV:
|
|
case VKI_SIOCSIWSTATS:
|
|
case VKI_SIOCSIWSPY:
|
|
case VKI_SIOCSIWTHRSPY:
|
|
case VKI_SIOCSIWAP:
|
|
case VKI_SIOCSIWSCAN:
|
|
case VKI_SIOCSIWESSID:
|
|
case VKI_SIOCSIWRATE:
|
|
case VKI_SIOCSIWNICKN:
|
|
case VKI_SIOCSIWRTS:
|
|
case VKI_SIOCSIWFRAG:
|
|
case VKI_SIOCSIWTXPOW:
|
|
case VKI_SIOCSIWRETRY:
|
|
case VKI_SIOCSIWENCODE:
|
|
case VKI_SIOCSIWPOWER:
|
|
case VKI_SIOCSIWGENIE:
|
|
case VKI_SIOCSIWMLME:
|
|
case VKI_SIOCSIWAUTH:
|
|
case VKI_SIOCSIWENCODEEXT:
|
|
case VKI_SIOCSIWPMKSA:
|
|
break;
|
|
case VKI_SIOCGIWNAME:
|
|
if (ARG3) {
|
|
POST_MEM_WRITE((Addr)((struct vki_iwreq *)(Addr)ARG3)->u.name,
|
|
sizeof(((struct vki_iwreq *)(Addr)ARG3)->u.name));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWNWID:
|
|
case VKI_SIOCGIWSENS:
|
|
case VKI_SIOCGIWRATE:
|
|
case VKI_SIOCGIWRTS:
|
|
case VKI_SIOCGIWFRAG:
|
|
case VKI_SIOCGIWTXPOW:
|
|
case VKI_SIOCGIWRETRY:
|
|
case VKI_SIOCGIWPOWER:
|
|
case VKI_SIOCGIWAUTH:
|
|
if (ARG3) {
|
|
POST_MEM_WRITE((Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.param,
|
|
sizeof(struct vki_iw_param));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWFREQ:
|
|
if (ARG3) {
|
|
POST_MEM_WRITE((Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.freq,
|
|
sizeof(struct vki_iw_freq));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWMODE:
|
|
if (ARG3) {
|
|
POST_MEM_WRITE((Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.mode,
|
|
sizeof(__vki_u32));
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWRANGE:
|
|
case VKI_SIOCGIWPRIV:
|
|
case VKI_SIOCGIWSTATS:
|
|
case VKI_SIOCGIWSPY:
|
|
case VKI_SIOCGIWTHRSPY:
|
|
case VKI_SIOCGIWAPLIST:
|
|
case VKI_SIOCGIWSCAN:
|
|
case VKI_SIOCGIWESSID:
|
|
case VKI_SIOCGIWNICKN:
|
|
case VKI_SIOCGIWENCODE:
|
|
case VKI_SIOCGIWGENIE:
|
|
case VKI_SIOCGIWENCODEEXT:
|
|
if (ARG3) {
|
|
struct vki_iw_point* point;
|
|
point = &((struct vki_iwreq *)(Addr)ARG3)->u.data;
|
|
POST_MEM_WRITE((Addr)point->pointer, point->length);
|
|
}
|
|
break;
|
|
case VKI_SIOCGIWAP:
|
|
if (ARG3) {
|
|
POST_MEM_WRITE((Addr)&((struct vki_iwreq *)(Addr)ARG3)->u.ap_addr,
|
|
sizeof(struct vki_sockaddr));
|
|
}
|
|
break;
|
|
|
|
# if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
|
|
|| defined(VGPV_mips32_linux_android) \
|
|
|| defined(VGPV_arm64_linux_android)
|
|
/* ashmem */
|
|
case VKI_ASHMEM_GET_SIZE:
|
|
case VKI_ASHMEM_SET_SIZE:
|
|
case VKI_ASHMEM_GET_PROT_MASK:
|
|
case VKI_ASHMEM_SET_PROT_MASK:
|
|
case VKI_ASHMEM_GET_PIN_STATUS:
|
|
case VKI_ASHMEM_PURGE_ALL_CACHES:
|
|
case VKI_ASHMEM_SET_NAME:
|
|
case VKI_ASHMEM_PIN:
|
|
case VKI_ASHMEM_UNPIN:
|
|
break;
|
|
case VKI_ASHMEM_GET_NAME:
|
|
POST_MEM_WRITE( ARG3, VKI_ASHMEM_NAME_LEN );
|
|
break;
|
|
|
|
/* binder */
|
|
case VKI_BINDER_WRITE_READ:
|
|
if (ARG3) {
|
|
struct vki_binder_write_read* bwr
|
|
= (struct vki_binder_write_read*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(bwr->write_consumed);
|
|
POST_FIELD_WRITE(bwr->read_consumed);
|
|
|
|
if (bwr->read_size)
|
|
POST_MEM_WRITE((Addr)bwr->read_buffer, bwr->read_consumed);
|
|
}
|
|
break;
|
|
|
|
case VKI_BINDER_SET_IDLE_TIMEOUT:
|
|
case VKI_BINDER_SET_MAX_THREADS:
|
|
case VKI_BINDER_SET_IDLE_PRIORITY:
|
|
case VKI_BINDER_SET_CONTEXT_MGR:
|
|
case VKI_BINDER_THREAD_EXIT:
|
|
break;
|
|
case VKI_BINDER_VERSION:
|
|
if (ARG3) {
|
|
struct vki_binder_version* bv =
|
|
(struct vki_binder_version*)(Addr)ARG3;
|
|
POST_FIELD_WRITE(bv->protocol_version);
|
|
}
|
|
break;
|
|
# endif /* defined(VGPV_*_linux_android) */
|
|
|
|
case VKI_HCIGETDEVLIST:
|
|
if (ARG3) {
|
|
struct vki_hci_dev_list_req* dlr =
|
|
(struct vki_hci_dev_list_req*)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)ARG3 + sizeof(struct vki_hci_dev_list_req),
|
|
dlr->dev_num * sizeof(struct vki_hci_dev_req));
|
|
}
|
|
break;
|
|
|
|
case VKI_HCIINQUIRY:
|
|
if (ARG3) {
|
|
struct vki_hci_inquiry_req* ir =
|
|
(struct vki_hci_inquiry_req*)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)ARG3 + sizeof(struct vki_hci_inquiry_req),
|
|
ir->num_rsp * sizeof(struct vki_inquiry_info));
|
|
}
|
|
break;
|
|
|
|
case VKI_DRM_IOCTL_VERSION:
|
|
if (ARG3) {
|
|
struct vki_drm_version* data = (struct vki_drm_version *)(Addr)ARG3;
|
|
struct vg_drm_version_info* info = container_of(data, struct vg_drm_version_info, data);
|
|
const vki_size_t orig_name_len = info->orig->name_len;
|
|
const vki_size_t orig_date_len = info->orig->date_len;
|
|
const vki_size_t orig_desc_len = info->orig->desc_len;
|
|
*info->orig = info->data;
|
|
ARG3 = (Addr)info->orig;
|
|
data = info->orig;
|
|
VG_(free)(info);
|
|
if (SUCCESS) {
|
|
POST_MEM_WRITE((Addr)&data->version_major, sizeof(data->version_major));
|
|
POST_MEM_WRITE((Addr)&data->version_minor, sizeof(data->version_minor));
|
|
POST_MEM_WRITE((Addr)&data->version_patchlevel, sizeof(data->version_patchlevel));
|
|
POST_MEM_WRITE((Addr)&data->name_len, sizeof(data->name_len));
|
|
POST_MEM_WRITE((Addr)data->name, VG_MIN(data->name_len, orig_name_len));
|
|
POST_MEM_WRITE((Addr)&data->date_len, sizeof(data->date_len));
|
|
POST_MEM_WRITE((Addr)data->date, VG_MIN(data->date_len, orig_date_len));
|
|
POST_MEM_WRITE((Addr)&data->desc_len, sizeof(data->desc_len));
|
|
POST_MEM_WRITE((Addr)data->desc, VG_MIN(data->desc_len, orig_desc_len));
|
|
}
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GET_UNIQUE:
|
|
if (ARG3) {
|
|
struct vki_drm_unique *data = (struct vki_drm_unique *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->unique, sizeof(data->unique_len));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GET_MAGIC:
|
|
if (ARG3) {
|
|
struct vki_drm_auth *data = (struct vki_drm_auth *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->magic, sizeof(data->magic));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_WAIT_VBLANK:
|
|
if (ARG3) {
|
|
union vki_drm_wait_vblank *data =
|
|
(union vki_drm_wait_vblank *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->reply, sizeof(data->reply));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GEM_FLINK:
|
|
if (ARG3) {
|
|
struct vki_drm_gem_flink *data =
|
|
(struct vki_drm_gem_flink *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->name, sizeof(data->name));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_GEM_OPEN:
|
|
if (ARG3) {
|
|
struct vki_drm_gem_open *data = (struct vki_drm_gem_open *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->handle, sizeof(data->handle));
|
|
POST_MEM_WRITE((Addr)&data->size, sizeof(data->size));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GETPARAM:
|
|
if (ARG3) {
|
|
vki_drm_i915_getparam_t *data = (vki_drm_i915_getparam_t *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->value, sizeof(int));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_BUSY:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_busy *data =
|
|
(struct vki_drm_i915_gem_busy *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->busy, sizeof(data->busy));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_CREATE:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_create *data =
|
|
(struct vki_drm_i915_gem_create *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->handle, sizeof(data->handle));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_PREAD:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_pread *data =
|
|
(struct vki_drm_i915_gem_pread *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->data_ptr, data->size);
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAPv1:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap_v1 *data =
|
|
(struct vki_drm_i915_gem_mmap_v1 *)(Addr)ARG3;
|
|
Addr addr = data->addr_ptr;
|
|
SizeT size = data->size;
|
|
vg_assert(ML_(valid_client_addr)(addr, size, tid,
|
|
"ioctl(DRM_IOCTL_I915_GEM_MMAPv1)"));
|
|
ML_(notify_core_and_tool_of_mmap)(addr, size,
|
|
VKI_PROT_READ | VKI_PROT_WRITE,
|
|
VKI_MAP_ANONYMOUS, -1, 0 );
|
|
POST_MEM_WRITE((Addr)&data->addr_ptr, sizeof(data->addr_ptr));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAP:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap *data =
|
|
(struct vki_drm_i915_gem_mmap *)(Addr)ARG3;
|
|
Addr addr = data->addr_ptr;
|
|
SizeT size = data->size;
|
|
vg_assert(ML_(valid_client_addr)(addr, size, tid,
|
|
"ioctl(DRM_IOCTL_I915_GEM_MMAP)"));
|
|
ML_(notify_core_and_tool_of_mmap)(addr, size,
|
|
VKI_PROT_READ | VKI_PROT_WRITE,
|
|
VKI_MAP_ANONYMOUS, -1, 0 );
|
|
POST_MEM_WRITE((Addr)&data->addr_ptr, sizeof(data->addr_ptr));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_MMAP_GTT:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_mmap_gtt *data =
|
|
(struct vki_drm_i915_gem_mmap_gtt *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->offset, sizeof(data->offset));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_SET_TILING:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_set_tiling *data =
|
|
(struct vki_drm_i915_gem_set_tiling *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->tiling_mode, sizeof(data->tiling_mode));
|
|
POST_MEM_WRITE((Addr)&data->stride, sizeof(data->stride));
|
|
POST_MEM_WRITE((Addr)&data->swizzle_mode, sizeof(data->swizzle_mode));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_GET_TILING:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_get_tiling *data =
|
|
(struct vki_drm_i915_gem_get_tiling *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->tiling_mode, sizeof(data->tiling_mode));
|
|
POST_MEM_WRITE((Addr)&data->swizzle_mode, sizeof(data->swizzle_mode));
|
|
}
|
|
break;
|
|
case VKI_DRM_IOCTL_I915_GEM_GET_APERTURE:
|
|
if (ARG3) {
|
|
struct vki_drm_i915_gem_get_aperture *data =
|
|
(struct vki_drm_i915_gem_get_aperture *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->aper_size, sizeof(data->aper_size));
|
|
POST_MEM_WRITE((Addr)&data->aper_available_size, sizeof(data->aper_available_size));
|
|
}
|
|
break;
|
|
|
|
/* KVM ioctls that only write the system call return value */
|
|
case VKI_KVM_GET_API_VERSION:
|
|
case VKI_KVM_CREATE_VM:
|
|
case VKI_KVM_CHECK_EXTENSION:
|
|
case VKI_KVM_GET_VCPU_MMAP_SIZE:
|
|
case VKI_KVM_S390_ENABLE_SIE:
|
|
case VKI_KVM_CREATE_VCPU:
|
|
case VKI_KVM_SET_TSS_ADDR:
|
|
case VKI_KVM_CREATE_IRQCHIP:
|
|
case VKI_KVM_RUN:
|
|
case VKI_KVM_S390_INITIAL_RESET:
|
|
case VKI_KVM_KVMCLOCK_CTRL:
|
|
break;
|
|
|
|
case VKI_KVM_S390_MEM_OP: {
|
|
struct vki_kvm_s390_mem_op *args =
|
|
(struct vki_kvm_s390_mem_op *)(Addr)(ARG3);
|
|
if (args->flags & VKI_KVM_S390_MEMOP_F_CHECK_ONLY)
|
|
break;
|
|
if (args->op == VKI_KVM_S390_MEMOP_LOGICAL_READ)
|
|
POST_MEM_WRITE((Addr)args->buf, args->size);
|
|
}
|
|
break;
|
|
|
|
#ifdef ENABLE_XEN
|
|
case VKI_XEN_IOCTL_PRIVCMD_HYPERCALL: {
|
|
SyscallArgs harrghs;
|
|
struct vki_xen_privcmd_hypercall *args =
|
|
(struct vki_xen_privcmd_hypercall *)(Addr)(ARG3);
|
|
|
|
if (!args)
|
|
break;
|
|
|
|
VG_(memset)(&harrghs, 0, sizeof(harrghs));
|
|
harrghs.sysno = args->op;
|
|
harrghs.arg1 = args->arg[0];
|
|
harrghs.arg2 = args->arg[1];
|
|
harrghs.arg3 = args->arg[2];
|
|
harrghs.arg4 = args->arg[3];
|
|
harrghs.arg5 = args->arg[4];
|
|
harrghs.arg6 = harrghs.arg7 = harrghs.arg8 = 0;
|
|
|
|
WRAPPER_POST_NAME(xen, hypercall) (tid, &harrghs, status);
|
|
}
|
|
break;
|
|
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAP:
|
|
break;
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH: {
|
|
struct vki_xen_privcmd_mmapbatch *args =
|
|
(struct vki_xen_privcmd_mmapbatch *)(Addr)(ARG3);
|
|
POST_MEM_WRITE((Addr)args->arr, sizeof(*(args->arr)) * args->num);
|
|
}
|
|
break;
|
|
case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2: {
|
|
struct vki_xen_privcmd_mmapbatch_v2 *args =
|
|
(struct vki_xen_privcmd_mmapbatch_v2 *)(Addr)(ARG3);
|
|
POST_MEM_WRITE((Addr)args->err, sizeof(*(args->err)) * args->num);
|
|
}
|
|
break;
|
|
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_VIRQ:
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_INTERDOMAIN:
|
|
case VKI_XEN_IOCTL_EVTCHN_BIND_UNBOUND_PORT:
|
|
case VKI_XEN_IOCTL_EVTCHN_UNBIND:
|
|
case VKI_XEN_IOCTL_EVTCHN_NOTIFY:
|
|
case VKI_XEN_IOCTL_EVTCHN_RESET:
|
|
/* No output */
|
|
break;
|
|
#endif
|
|
|
|
/* Lustre */
|
|
case VKI_OBD_IOC_FID2PATH: {
|
|
struct vki_getinfo_fid2path *args = (void *)(Addr)(ARG3);
|
|
POST_FIELD_WRITE(args->gf_recno);
|
|
POST_FIELD_WRITE(args->gf_linkno);
|
|
POST_MEM_WRITE((Addr)args->gf_path, VG_(strlen)(args->gf_path)+1);
|
|
break;
|
|
}
|
|
|
|
case VKI_LL_IOC_PATH2FID:
|
|
POST_MEM_WRITE(ARG3, sizeof(struct vki_lu_fid));
|
|
break;
|
|
|
|
case VKI_LL_IOC_GETPARENT: {
|
|
struct vki_getparent *gp = (struct vki_getparent *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(gp->gp_fid);
|
|
POST_MEM_WRITE((Addr)gp->gp_name, VG_(strlen)(gp->gp_name)+1);
|
|
break;
|
|
}
|
|
|
|
/* V4L2 */
|
|
case VKI_V4L2_S_FMT:
|
|
case VKI_V4L2_TRY_FMT:
|
|
case VKI_V4L2_REQBUFS:
|
|
case VKI_V4L2_OVERLAY:
|
|
case VKI_V4L2_STREAMON:
|
|
case VKI_V4L2_STREAMOFF:
|
|
case VKI_V4L2_S_PARM:
|
|
case VKI_V4L2_S_STD:
|
|
case VKI_V4L2_S_FREQUENCY:
|
|
case VKI_V4L2_S_CTRL:
|
|
case VKI_V4L2_S_TUNER:
|
|
case VKI_V4L2_S_AUDIO:
|
|
case VKI_V4L2_S_INPUT:
|
|
case VKI_V4L2_S_EDID:
|
|
case VKI_V4L2_S_OUTPUT:
|
|
case VKI_V4L2_S_AUDOUT:
|
|
case VKI_V4L2_S_MODULATOR:
|
|
case VKI_V4L2_S_JPEGCOMP:
|
|
case VKI_V4L2_S_CROP:
|
|
case VKI_V4L2_S_PRIORITY:
|
|
case VKI_V4L2_S_HW_FREQ_SEEK:
|
|
case VKI_V4L2_S_DV_TIMINGS:
|
|
case VKI_V4L2_SUBSCRIBE_EVENT:
|
|
case VKI_V4L2_UNSUBSCRIBE_EVENT:
|
|
case VKI_V4L2_PREPARE_BUF:
|
|
break;
|
|
case VKI_V4L2_QUERYCAP: {
|
|
struct vki_v4l2_capability *data =
|
|
(struct vki_v4l2_capability *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FMT: {
|
|
struct vki_v4l2_fmtdesc *data = (struct vki_v4l2_fmtdesc *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->flags);
|
|
POST_FIELD_WRITE(data->description);
|
|
POST_FIELD_WRITE(data->pixelformat);
|
|
POST_FIELD_WRITE(data->reserved);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FMT: {
|
|
struct vki_v4l2_format *data = (struct vki_v4l2_format *)(Addr)ARG3;
|
|
switch (data->type) {
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
POST_FIELD_WRITE(data->fmt.pix);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
POST_FIELD_WRITE(data->fmt.vbi);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
POST_FIELD_WRITE(data->fmt.sliced);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
POST_FIELD_WRITE(data->fmt.win);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
POST_FIELD_WRITE(data->fmt.pix_mp);
|
|
break;
|
|
case VKI_V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
POST_FIELD_WRITE(data->fmt.sdr);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYBUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
for (i = 0; i < data->length; i++) {
|
|
POST_FIELD_WRITE(data->m.planes[i].bytesused);
|
|
POST_FIELD_WRITE(data->m.planes[i].length);
|
|
POST_FIELD_WRITE(data->m.planes[i].m);
|
|
POST_FIELD_WRITE(data->m.planes[i].data_offset);
|
|
POST_FIELD_WRITE(data->m.planes[i].reserved);
|
|
}
|
|
} else {
|
|
POST_FIELD_WRITE(data->m);
|
|
POST_FIELD_WRITE(data->length);
|
|
}
|
|
POST_FIELD_WRITE(data->bytesused);
|
|
POST_FIELD_WRITE(data->flags);
|
|
POST_FIELD_WRITE(data->field);
|
|
POST_FIELD_WRITE(data->timestamp);
|
|
POST_FIELD_WRITE(data->timecode);
|
|
POST_FIELD_WRITE(data->sequence);
|
|
POST_FIELD_WRITE(data->memory);
|
|
POST_FIELD_WRITE(data->sequence);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FBUF: {
|
|
struct vki_v4l2_framebuffer *data =
|
|
(struct vki_v4l2_framebuffer *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_FBUF: {
|
|
struct vki_v4l2_framebuffer *data =
|
|
(struct vki_v4l2_framebuffer *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->capability);
|
|
POST_FIELD_WRITE(data->flags);
|
|
POST_FIELD_WRITE(data->fmt);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QBUF: {
|
|
struct vki_v4l2_buffer *data = (struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
for (i = 0; i < data->length; i++) {
|
|
POST_FIELD_WRITE(data->m.planes[i].length);
|
|
if (data->memory == VKI_V4L2_MEMORY_MMAP)
|
|
POST_FIELD_WRITE(data->m.planes[i].m);
|
|
}
|
|
} else {
|
|
if (data->memory == VKI_V4L2_MEMORY_MMAP)
|
|
POST_FIELD_WRITE(data->m);
|
|
POST_FIELD_WRITE(data->length);
|
|
}
|
|
break;
|
|
}
|
|
case VKI_V4L2_EXPBUF: {
|
|
struct vki_v4l2_exportbuffer *data =
|
|
(struct vki_v4l2_exportbuffer *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->fd);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DQBUF: {
|
|
struct vki_v4l2_buffer *data =
|
|
(struct vki_v4l2_buffer *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->index);
|
|
POST_FIELD_WRITE(data->bytesused);
|
|
POST_FIELD_WRITE(data->field);
|
|
if (data->type == VKI_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
unsigned i;
|
|
|
|
for (i = 0; i < data->length; i++) {
|
|
POST_FIELD_WRITE(data->m.planes[i].bytesused);
|
|
POST_FIELD_WRITE(data->m.planes[i].data_offset);
|
|
POST_FIELD_WRITE(data->m.planes[i].length);
|
|
POST_FIELD_WRITE(data->m.planes[i].m);
|
|
}
|
|
} else {
|
|
POST_FIELD_WRITE(data->m);
|
|
POST_FIELD_WRITE(data->length);
|
|
POST_FIELD_WRITE(data->bytesused);
|
|
POST_FIELD_WRITE(data->field);
|
|
}
|
|
POST_FIELD_WRITE(data->timestamp);
|
|
POST_FIELD_WRITE(data->timecode);
|
|
POST_FIELD_WRITE(data->sequence);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_PARM: {
|
|
struct vki_v4l2_streamparm *data =
|
|
(struct vki_v4l2_streamparm *)(Addr)ARG3;
|
|
int is_output = data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
|
|
data->type == VKI_V4L2_BUF_TYPE_VBI_OUTPUT ||
|
|
data->type == VKI_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
|
|
|
|
if (is_output)
|
|
POST_MEM_WRITE((Addr)&data->parm.output,
|
|
sizeof(data->parm.output) - sizeof(data->parm.output.reserved));
|
|
else
|
|
POST_MEM_WRITE((Addr)&data->parm.capture,
|
|
sizeof(data->parm.capture) - sizeof(data->parm.capture.reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_STD: {
|
|
vki_v4l2_std_id *data = (vki_v4l2_std_id *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMSTD: {
|
|
struct vki_v4l2_standard *data = (struct vki_v4l2_standard *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->id, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMINPUT: {
|
|
struct vki_v4l2_input *data = (struct vki_v4l2_input *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_CTRL: {
|
|
struct vki_v4l2_control *data = (struct vki_v4l2_control *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->value);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_TUNER: {
|
|
struct vki_v4l2_tuner *data = (struct vki_v4l2_tuner *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_AUDIO: {
|
|
struct vki_v4l2_audio *data = (struct vki_v4l2_audio *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data,
|
|
sizeof(*data) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYCTRL: {
|
|
struct vki_v4l2_queryctrl *data = (struct vki_v4l2_queryctrl *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->type,
|
|
sizeof(*data) - sizeof(data->id));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYMENU: {
|
|
struct vki_v4l2_querymenu *data = (struct vki_v4l2_querymenu *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name,
|
|
sizeof(*data) - sizeof(data->id) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_INPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_EDID: {
|
|
struct vki_v4l2_edid *data = (struct vki_v4l2_edid *)(Addr)ARG3;
|
|
if (data->blocks && data->edid)
|
|
POST_MEM_WRITE((Addr)data->edid, data->blocks * 128);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_OUTPUT: {
|
|
int *data = (int *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMOUTPUT: {
|
|
struct vki_v4l2_output *data = (struct vki_v4l2_output *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name, sizeof(*data) - sizeof(data->index));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_AUDOUT: {
|
|
struct vki_v4l2_audioout *data = (struct vki_v4l2_audioout *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data,
|
|
sizeof(*data) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_MODULATOR: {
|
|
struct vki_v4l2_modulator *data = (struct vki_v4l2_modulator *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_FREQUENCY: {
|
|
struct vki_v4l2_frequency *data = (struct vki_v4l2_frequency *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->type);
|
|
POST_FIELD_WRITE(data->frequency);
|
|
break;
|
|
}
|
|
case VKI_V4L2_CROPCAP: {
|
|
struct vki_v4l2_cropcap *data = (struct vki_v4l2_cropcap *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->bounds, sizeof(*data) - sizeof(data->type));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_CROP: {
|
|
struct vki_v4l2_crop *data = (struct vki_v4l2_crop *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->c);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_JPEGCOMP: {
|
|
struct vki_v4l2_jpegcompression *data =
|
|
(struct vki_v4l2_jpegcompression *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERYSTD: {
|
|
vki_v4l2_std_id *data = (vki_v4l2_std_id *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMAUDIO: {
|
|
struct vki_v4l2_audio *data = (struct vki_v4l2_audio *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUMAUDOUT: {
|
|
struct vki_v4l2_audioout *data = (struct vki_v4l2_audioout *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name,
|
|
sizeof(*data) - sizeof(data->index) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_PRIORITY: {
|
|
__vki_u32 *data = (__vki_u32 *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_SLICED_VBI_CAP: {
|
|
struct vki_v4l2_sliced_vbi_cap *data =
|
|
(struct vki_v4l2_sliced_vbi_cap *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data,
|
|
sizeof(*data) - sizeof(data->type) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
if (data->count) {
|
|
unsigned i;
|
|
|
|
for (i = 0; i < data->count; i++) {
|
|
if (data->controls[i].size)
|
|
POST_MEM_WRITE((Addr)data->controls[i].ptr, data->controls[i].size);
|
|
else
|
|
POST_FIELD_WRITE(data->controls[i].value64);
|
|
}
|
|
}
|
|
POST_FIELD_WRITE(data->error_idx);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->error_idx);
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_EXT_CTRLS: {
|
|
struct vki_v4l2_ext_controls *data =
|
|
(struct vki_v4l2_ext_controls *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->error_idx);
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FRAMESIZES: {
|
|
struct vki_v4l2_frmsizeenum *data =
|
|
(struct vki_v4l2_frmsizeenum *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->type);
|
|
POST_FIELD_WRITE(data->stepwise);
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FRAMEINTERVALS: {
|
|
struct vki_v4l2_frmivalenum *data =
|
|
(struct vki_v4l2_frmivalenum *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->type);
|
|
POST_FIELD_WRITE(data->stepwise);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_ENC_INDEX: {
|
|
struct vki_v4l2_enc_idx *data = (struct vki_v4l2_enc_idx *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENCODER_CMD: {
|
|
struct vki_v4l2_encoder_cmd *data =
|
|
(struct vki_v4l2_encoder_cmd *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->flags);
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_ENCODER_CMD: {
|
|
struct vki_v4l2_encoder_cmd *data =
|
|
(struct vki_v4l2_encoder_cmd *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->flags);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_S_REGISTER: {
|
|
struct vki_v4l2_dbg_register *data =
|
|
(struct vki_v4l2_dbg_register *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->size);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_G_REGISTER: {
|
|
struct vki_v4l2_dbg_register *data =
|
|
(struct vki_v4l2_dbg_register *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->val);
|
|
POST_FIELD_WRITE(data->size);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_DV_TIMINGS: {
|
|
struct vki_v4l2_dv_timings *data =
|
|
(struct vki_v4l2_dv_timings *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DQEVENT: {
|
|
struct vki_v4l2_event *data = (struct vki_v4l2_event *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_CREATE_BUFS: {
|
|
struct vki_v4l2_create_buffers *data =
|
|
(struct vki_v4l2_create_buffers *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->index);
|
|
break;
|
|
}
|
|
case VKI_V4L2_G_SELECTION: {
|
|
struct vki_v4l2_selection *data =
|
|
(struct vki_v4l2_selection *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->r);
|
|
break;
|
|
}
|
|
case VKI_V4L2_S_SELECTION: {
|
|
struct vki_v4l2_selection *data = (struct vki_v4l2_selection *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->r);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DECODER_CMD: {
|
|
struct vki_v4l2_decoder_cmd *data =
|
|
(struct vki_v4l2_decoder_cmd *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->flags);
|
|
break;
|
|
}
|
|
case VKI_V4L2_TRY_DECODER_CMD: {
|
|
struct vki_v4l2_decoder_cmd *data =
|
|
(struct vki_v4l2_decoder_cmd *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->flags);
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_DV_TIMINGS: {
|
|
struct vki_v4l2_enum_dv_timings *data =
|
|
(struct vki_v4l2_enum_dv_timings *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->timings);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERY_DV_TIMINGS: {
|
|
struct vki_v4l2_dv_timings *data =
|
|
(struct vki_v4l2_dv_timings *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_DV_TIMINGS_CAP: {
|
|
struct vki_v4l2_dv_timings_cap *data =
|
|
(struct vki_v4l2_dv_timings_cap *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_V4L2_ENUM_FREQ_BANDS: {
|
|
struct vki_v4l2_frequency_band *data =
|
|
(struct vki_v4l2_frequency_band *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->capability);
|
|
POST_FIELD_WRITE(data->rangelow);
|
|
POST_FIELD_WRITE(data->rangehigh);
|
|
POST_FIELD_WRITE(data->modulation);
|
|
break;
|
|
}
|
|
case VKI_V4L2_DBG_G_CHIP_INFO: {
|
|
struct vki_v4l2_dbg_chip_info *data =
|
|
(struct vki_v4l2_dbg_chip_info *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->name);
|
|
POST_FIELD_WRITE(data->flags);
|
|
break;
|
|
}
|
|
case VKI_V4L2_QUERY_EXT_CTRL: {
|
|
struct vki_v4l2_query_ext_ctrl *data =
|
|
(struct vki_v4l2_query_ext_ctrl *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)&data->type,
|
|
sizeof(*data) - sizeof(data->id) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
|
|
case VKI_V4L2_SUBDEV_S_FMT:
|
|
case VKI_V4L2_SUBDEV_S_FRAME_INTERVAL:
|
|
case VKI_V4L2_SUBDEV_S_CROP:
|
|
case VKI_V4L2_SUBDEV_S_SELECTION:
|
|
break;
|
|
|
|
case VKI_V4L2_SUBDEV_G_FMT: {
|
|
struct vki_v4l2_subdev_format *data =
|
|
(struct vki_v4l2_subdev_format *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->format);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_FRAME_INTERVAL: {
|
|
struct vki_v4l2_subdev_frame_interval *data =
|
|
(struct vki_v4l2_subdev_frame_interval *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->interval);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_MBUS_CODE: {
|
|
struct vki_v4l2_subdev_mbus_code_enum *data =
|
|
(struct vki_v4l2_subdev_mbus_code_enum *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->code);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_FRAME_SIZE: {
|
|
struct vki_v4l2_subdev_frame_size_enum *data =
|
|
(struct vki_v4l2_subdev_frame_size_enum *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->min_width);
|
|
POST_FIELD_WRITE(data->min_height);
|
|
POST_FIELD_WRITE(data->max_width);
|
|
POST_FIELD_WRITE(data->max_height);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_ENUM_FRAME_INTERVAL: {
|
|
struct vki_v4l2_subdev_frame_interval_enum *data =
|
|
(struct vki_v4l2_subdev_frame_interval_enum *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->interval);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_CROP: {
|
|
struct vki_v4l2_subdev_crop *data =
|
|
(struct vki_v4l2_subdev_crop *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->rect);
|
|
break;
|
|
}
|
|
case VKI_V4L2_SUBDEV_G_SELECTION: {
|
|
struct vki_v4l2_subdev_selection *data =
|
|
(struct vki_v4l2_subdev_selection *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->r);
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_DEVICE_INFO: {
|
|
struct vki_media_device_info *data =
|
|
(struct vki_media_device_info *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data) - sizeof(data->reserved));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_ENUM_ENTITIES: {
|
|
struct vki_media_entity_desc *data =
|
|
(struct vki_media_entity_desc *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->name, sizeof(*data) - sizeof(data->id));
|
|
break;
|
|
}
|
|
case VKI_MEDIA_IOC_ENUM_LINKS:
|
|
/*
|
|
* This ioctl does write to the provided pointers, but it's not
|
|
* possible to deduce the size of the array those pointers point to.
|
|
*/
|
|
break;
|
|
case VKI_MEDIA_IOC_SETUP_LINK:
|
|
break;
|
|
|
|
/* Serial */
|
|
case VKI_TIOCGSERIAL: {
|
|
struct vki_serial_struct *data = (struct vki_serial_struct *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_TIOCSSERIAL:
|
|
break;
|
|
|
|
case VKI_PERF_EVENT_IOC_ENABLE:
|
|
case VKI_PERF_EVENT_IOC_DISABLE:
|
|
case VKI_PERF_EVENT_IOC_REFRESH:
|
|
case VKI_PERF_EVENT_IOC_RESET:
|
|
case VKI_PERF_EVENT_IOC_PERIOD:
|
|
case VKI_PERF_EVENT_IOC_SET_OUTPUT:
|
|
case VKI_PERF_EVENT_IOC_SET_FILTER:
|
|
case VKI_PERF_EVENT_IOC_SET_BPF:
|
|
break;
|
|
|
|
case VKI_PERF_EVENT_IOC_ID:
|
|
POST_MEM_WRITE((Addr)ARG3, sizeof(__vki_u64));
|
|
break;
|
|
|
|
/* Pulse Per Second (PPS) */
|
|
case VKI_PPS_GETPARAMS: {
|
|
struct vki_pps_kparams *data = (struct vki_pps_kparams *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PPS_GETCAP:
|
|
POST_MEM_WRITE((Addr)ARG3, sizeof(int));
|
|
break;
|
|
case VKI_PPS_FETCH: {
|
|
struct vki_pps_fdata *data = (struct vki_pps_fdata *)(Addr)ARG3;
|
|
POST_FIELD_WRITE(data->info);
|
|
break;
|
|
}
|
|
case VKI_PPS_SETPARAMS:
|
|
case VKI_PPS_KC_BIND:
|
|
break;
|
|
|
|
/* PTP Hardware Clock */
|
|
case VKI_PTP_CLOCK_GETCAPS: {
|
|
struct vki_ptp_clock_caps *data =
|
|
(struct vki_ptp_clock_caps *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_SYS_OFFSET: {
|
|
struct vki_ptp_sys_offset *data =
|
|
(struct vki_ptp_sys_offset *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->ts,
|
|
(2 * data->n_samples + 1) * sizeof(data->ts[0]));
|
|
break;
|
|
}
|
|
case VKI_PTP_PIN_GETFUNC: {
|
|
struct vki_ptp_pin_desc *data = (struct vki_ptp_pin_desc *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_SYS_OFFSET_PRECISE: {
|
|
struct vki_ptp_sys_offset_precise *data =
|
|
(struct vki_ptp_sys_offset_precise *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data, sizeof(*data));
|
|
break;
|
|
}
|
|
case VKI_PTP_SYS_OFFSET_EXTENDED: {
|
|
struct vki_ptp_sys_offset_extended *data =
|
|
(struct vki_ptp_sys_offset_extended *)(Addr)ARG3;
|
|
POST_MEM_WRITE((Addr)data->ts,
|
|
3 * data->n_samples * sizeof(data->ts[0][0]));
|
|
break;
|
|
}
|
|
case VKI_PTP_EXTTS_REQUEST:
|
|
case VKI_PTP_PEROUT_REQUEST:
|
|
case VKI_PTP_ENABLE_PPS:
|
|
case VKI_PTP_PIN_SETFUNC:
|
|
break;
|
|
|
|
default:
|
|
/* EVIOC* are variable length and return size written on success */
|
|
switch (ARG2 & ~(_VKI_IOC_SIZEMASK << _VKI_IOC_SIZESHIFT)) {
|
|
case VKI_EVIOCGNAME(0):
|
|
case VKI_EVIOCGPHYS(0):
|
|
case VKI_EVIOCGUNIQ(0):
|
|
case VKI_EVIOCGKEY(0):
|
|
case VKI_EVIOCGLED(0):
|
|
case VKI_EVIOCGSND(0):
|
|
case VKI_EVIOCGSW(0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SYN,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_KEY,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_REL,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_ABS,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_MSC,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SW,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_LED,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_SND,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_REP,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_FF,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_PWR,0):
|
|
case VKI_EVIOCGBIT(VKI_EV_FF_STATUS,0):
|
|
if (RES > 0)
|
|
POST_MEM_WRITE(ARG3, RES);
|
|
break;
|
|
default:
|
|
ML_(POST_unknown_ioctl)(tid, RES, ARG2, ARG3);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
post_sys_ioctl__out:
|
|
{} /* keep C compilers happy */
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
socketcall wrapper helpers
|
|
------------------------------------------------------------------ */
|
|
|
|
void
|
|
ML_(linux_PRE_sys_getsockopt) ( ThreadId tid,
|
|
UWord arg0, UWord arg1, UWord arg2,
|
|
UWord arg3, UWord arg4 )
|
|
{
|
|
/* int getsockopt(int s, int level, int optname,
|
|
void *optval, socklen_t *optlen); */
|
|
Addr optval_p = arg3;
|
|
Addr optlen_p = arg4;
|
|
/* vg_assert(sizeof(socklen_t) == sizeof(UInt)); */
|
|
if (optval_p != (Addr)NULL) {
|
|
ML_(buf_and_len_pre_check) ( tid, optval_p, optlen_p,
|
|
"socketcall.getsockopt(optval)",
|
|
"socketcall.getsockopt(optlen)" );
|
|
if (arg1 == VKI_SOL_SCTP &&
|
|
(arg2 == VKI_SCTP_GET_PEER_ADDRS ||
|
|
arg2 == VKI_SCTP_GET_LOCAL_ADDRS))
|
|
{
|
|
struct vki_sctp_getaddrs *ga = (struct vki_sctp_getaddrs*)arg3;
|
|
int address_bytes = sizeof(struct vki_sockaddr_in6) * ga->addr_num;
|
|
PRE_MEM_WRITE( "socketcall.getsockopt(optval.addrs)",
|
|
(Addr)ga->addrs, address_bytes );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_POST_sys_getsockopt) ( ThreadId tid,
|
|
SysRes res,
|
|
UWord arg0, UWord arg1, UWord arg2,
|
|
UWord arg3, UWord arg4 )
|
|
{
|
|
Addr optval_p = arg3;
|
|
Addr optlen_p = arg4;
|
|
vg_assert(!sr_isError(res)); /* guaranteed by caller */
|
|
if (optval_p != (Addr)NULL) {
|
|
ML_(buf_and_len_post_check) ( tid, res, optval_p, optlen_p,
|
|
"socketcall.getsockopt(optlen_out)" );
|
|
if (arg1 == VKI_SOL_SCTP &&
|
|
(arg2 == VKI_SCTP_GET_PEER_ADDRS ||
|
|
arg2 == VKI_SCTP_GET_LOCAL_ADDRS))
|
|
{
|
|
struct vki_sctp_getaddrs *ga = (struct vki_sctp_getaddrs*)arg3;
|
|
struct vki_sockaddr *a = ga->addrs;
|
|
int i;
|
|
for (i = 0; i < ga->addr_num; i++) {
|
|
int sl = 0;
|
|
if (a->sa_family == VKI_AF_INET)
|
|
sl = sizeof(struct vki_sockaddr_in);
|
|
else if (a->sa_family == VKI_AF_INET6)
|
|
sl = sizeof(struct vki_sockaddr_in6);
|
|
else {
|
|
VG_(message)(Vg_UserMsg, "Warning: getsockopt: unhandled "
|
|
"address type %d\n", a->sa_family);
|
|
}
|
|
a = (struct vki_sockaddr*)((char*)a + sl);
|
|
}
|
|
POST_MEM_WRITE( (Addr)ga->addrs, (char*)a - (char*)ga->addrs );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_PRE_sys_setsockopt) ( ThreadId tid,
|
|
UWord arg0, UWord arg1, UWord arg2,
|
|
UWord arg3, UWord arg4 )
|
|
{
|
|
/* int setsockopt(int s, int level, int optname,
|
|
const void *optval, socklen_t optlen); */
|
|
Addr optval_p = arg3;
|
|
if (optval_p != (Addr)NULL) {
|
|
/*
|
|
* OK, let's handle at least some setsockopt levels and options
|
|
* ourselves, so we don't get false claims of references to
|
|
* uninitialized memory (such as padding in structures) and *do*
|
|
* check what pointers in the argument point to.
|
|
*/
|
|
if (arg1 == VKI_SOL_SOCKET && arg2 == VKI_SO_ATTACH_FILTER)
|
|
{
|
|
struct vki_sock_fprog *fp = (struct vki_sock_fprog *)optval_p;
|
|
|
|
/*
|
|
* struct sock_fprog has a 16-bit count of instructions,
|
|
* followed by a pointer to an array of those instructions.
|
|
* There's padding between those two elements.
|
|
*
|
|
* So that we don't bogusly complain about the padding bytes,
|
|
* we just report that we read len and and filter.
|
|
*
|
|
* We then make sure that what filter points to is valid.
|
|
*/
|
|
PRE_MEM_READ( "setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, &optval.len)",
|
|
(Addr)&fp->len, sizeof(fp->len) );
|
|
PRE_MEM_READ( "setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, &optval.filter)",
|
|
(Addr)&fp->filter, sizeof(fp->filter) );
|
|
|
|
/* len * sizeof (*filter) */
|
|
if (fp->filter != NULL)
|
|
{
|
|
PRE_MEM_READ( "setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, optval.filter)",
|
|
(Addr)(fp->filter),
|
|
fp->len * sizeof(*fp->filter) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PRE_MEM_READ( "socketcall.setsockopt(optval)",
|
|
arg3, /* optval */
|
|
arg4 /* optlen */ );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_PRE_sys_recvmmsg) ( ThreadId tid,
|
|
UWord arg1, UWord arg2, UWord arg3,
|
|
UWord arg4, UWord arg5 )
|
|
{
|
|
struct vki_mmsghdr *mmsg = (struct vki_mmsghdr *)arg2;
|
|
HChar name[40]; // large enough
|
|
UInt i;
|
|
for (i = 0; i < arg3; i++) {
|
|
VG_(sprintf)(name, "mmsg[%u].msg_hdr", i);
|
|
ML_(generic_PRE_sys_recvmsg)(tid, name, &mmsg[i].msg_hdr);
|
|
VG_(sprintf)(name, "recvmmsg(mmsg[%u].msg_len)", i);
|
|
PRE_MEM_WRITE( name, (Addr)&mmsg[i].msg_len, sizeof(mmsg[i].msg_len) );
|
|
}
|
|
if (arg5)
|
|
PRE_MEM_READ( "recvmmsg(timeout)", arg5, sizeof(struct vki_timespec) );
|
|
}
|
|
|
|
void
|
|
ML_(linux_POST_sys_recvmmsg) (ThreadId tid, UWord res,
|
|
UWord arg1, UWord arg2, UWord arg3,
|
|
UWord arg4, UWord arg5 )
|
|
{
|
|
if (res > 0) {
|
|
struct vki_mmsghdr *mmsg = (struct vki_mmsghdr *)arg2;
|
|
HChar name[32]; // large enough
|
|
UInt i;
|
|
for (i = 0; i < res; i++) {
|
|
VG_(sprintf)(name, "mmsg[%u].msg_hdr", i);
|
|
ML_(generic_POST_sys_recvmsg)(tid, name, &mmsg[i].msg_hdr, mmsg[i].msg_len);
|
|
POST_MEM_WRITE( (Addr)&mmsg[i].msg_len, sizeof(mmsg[i].msg_len) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_PRE_sys_sendmmsg) ( ThreadId tid,
|
|
UWord arg1, UWord arg2, UWord arg3, UWord arg4 )
|
|
{
|
|
struct vki_mmsghdr *mmsg = (struct vki_mmsghdr *)arg2;
|
|
HChar name[40]; // large enough
|
|
UInt i;
|
|
for (i = 0; i < arg3; i++) {
|
|
VG_(sprintf)(name, "mmsg[%u].msg_hdr", i);
|
|
ML_(generic_PRE_sys_sendmsg)(tid, name, &mmsg[i].msg_hdr);
|
|
VG_(sprintf)(name, "sendmmsg(mmsg[%u].msg_len)", i);
|
|
PRE_MEM_WRITE( name, (Addr)&mmsg[i].msg_len, sizeof(mmsg[i].msg_len) );
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_POST_sys_sendmmsg) (ThreadId tid, UWord res,
|
|
UWord arg1, UWord arg2, UWord arg3, UWord arg4 )
|
|
{
|
|
if (res > 0) {
|
|
struct vki_mmsghdr *mmsg = (struct vki_mmsghdr *)arg2;
|
|
UInt i;
|
|
for (i = 0; i < res; i++) {
|
|
POST_MEM_WRITE( (Addr)&mmsg[i].msg_len, sizeof(mmsg[i].msg_len) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
ptrace wrapper helpers
|
|
------------------------------------------------------------------ */
|
|
|
|
void
|
|
ML_(linux_POST_traceme) ( ThreadId tid )
|
|
{
|
|
ThreadState *tst = VG_(get_ThreadState)(tid);
|
|
tst->ptrace = VKI_PT_PTRACED;
|
|
}
|
|
|
|
void
|
|
ML_(linux_PRE_getregset) ( ThreadId tid, long arg3, long arg4 )
|
|
{
|
|
struct vki_iovec *iov = (struct vki_iovec *) arg4;
|
|
|
|
PRE_FIELD_READ("ptrace(getregset iovec->iov_base)", iov->iov_base);
|
|
PRE_FIELD_READ("ptrace(getregset iovec->iov_len)", iov->iov_len);
|
|
if (ML_(safe_to_deref)(iov, sizeof(struct vki_iovec))) {
|
|
PRE_MEM_WRITE("ptrace(getregset *(iovec->iov_base))",
|
|
(Addr) iov->iov_base, iov->iov_len);
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_PRE_setregset) ( ThreadId tid, long arg3, long arg4 )
|
|
{
|
|
struct vki_iovec *iov = (struct vki_iovec *) arg4;
|
|
|
|
PRE_FIELD_READ("ptrace(setregset iovec->iov_base)", iov->iov_base);
|
|
PRE_FIELD_READ("ptrace(setregset iovec->iov_len)", iov->iov_len);
|
|
if (ML_(safe_to_deref)(iov, sizeof(struct vki_iovec))) {
|
|
PRE_MEM_READ("ptrace(setregset *(iovec->iov_base))",
|
|
(Addr) iov->iov_base, iov->iov_len);
|
|
}
|
|
}
|
|
|
|
void
|
|
ML_(linux_POST_getregset) ( ThreadId tid, long arg3, long arg4 )
|
|
{
|
|
struct vki_iovec *iov = (struct vki_iovec *) arg4;
|
|
|
|
/* XXX: The actual amount of data written by the kernel might be
|
|
less than iov_len, depending on the regset (arg3). */
|
|
POST_MEM_WRITE((unsigned long) iov->iov_base, iov->iov_len);
|
|
}
|
|
|
|
PRE(sys_kcmp)
|
|
{
|
|
PRINT("kcmp ( %ld, %ld, %ld, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
|
|
SARG1, SARG2, SARG3, ARG4, ARG5);
|
|
switch (ARG3) {
|
|
case VKI_KCMP_VM: case VKI_KCMP_FILES: case VKI_KCMP_FS:
|
|
case VKI_KCMP_SIGHAND: case VKI_KCMP_IO: case VKI_KCMP_SYSVSEM:
|
|
/* Most of the comparison types don't look at |idx1| or
|
|
|idx2|. */
|
|
PRE_REG_READ3(long, "kcmp",
|
|
vki_pid_t, pid1, vki_pid_t, pid2, int, type);
|
|
break;
|
|
case VKI_KCMP_FILE:
|
|
default:
|
|
PRE_REG_READ5(long, "kcmp",
|
|
vki_pid_t, pid1, vki_pid_t, pid2, int, type,
|
|
unsigned long, idx1, unsigned long, idx2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
bpf wrappers
|
|
------------------------------------------------------------------ */
|
|
|
|
static Bool bpf_map_get_sizes(Int fd, UInt *key_size, UInt *value_size)
|
|
{
|
|
HChar path[32], buf[1024]; /* large enough */
|
|
SysRes sres;
|
|
HChar *comp;
|
|
Int proc_fd;
|
|
|
|
*key_size = 0;
|
|
*value_size = 0;
|
|
|
|
VG_(sprintf)(path, "/proc/%d/fdinfo/%d", VG_(getpid)(), fd);
|
|
sres = VG_(open)(path, VKI_O_RDONLY, 0);
|
|
if (sr_isError(sres))
|
|
return False;
|
|
proc_fd = sr_Res(sres);
|
|
|
|
if (VG_(read)(proc_fd, buf, sizeof(buf)) <= 0)
|
|
return False;
|
|
VG_(close)(proc_fd);
|
|
|
|
comp = VG_(strstr)(buf, "key_size:");
|
|
if (comp)
|
|
*key_size = VG_(strtoull10)(comp + sizeof("key_size:"), NULL);
|
|
|
|
comp = VG_(strstr)(buf, "value_size:");
|
|
if (comp)
|
|
*value_size = VG_(strtoull10)(comp + sizeof("value_size:"), NULL);
|
|
|
|
return (*key_size && *value_size);
|
|
}
|
|
|
|
/*
|
|
* From a file descriptor for an eBPF object, try to determine the size of the
|
|
* struct that will be written, i.e. determine if object is a map or a program.
|
|
* There is no direct way to do this, so parse /proc/<pid>/fdinfo/<fd> and
|
|
* search for strings "prog_type" or "map_type".
|
|
*/
|
|
static UInt bpf_obj_get_info_size(Int fd)
|
|
{
|
|
HChar path[32], buf[1024]; /* large enough */
|
|
SysRes sres;
|
|
Int proc_fd;
|
|
|
|
VG_(sprintf)(path, "/proc/%d/fdinfo/%d", VG_(getpid)(), fd);
|
|
sres = VG_(open)(path, VKI_O_RDONLY, 0);
|
|
if (sr_isError(sres))
|
|
return 0;
|
|
proc_fd = sr_Res(sres);
|
|
|
|
if (VG_(read)(proc_fd, buf, sizeof(buf)) <= 0)
|
|
return 0;
|
|
VG_(close)(proc_fd);
|
|
|
|
if (VG_(strstr)(buf, "prog_type:"))
|
|
return sizeof(struct vki_bpf_prog_info);
|
|
|
|
if (VG_(strstr)(buf, "map_type:"))
|
|
return sizeof(struct vki_bpf_map_info);
|
|
|
|
return 0;
|
|
}
|
|
|
|
PRE(sys_bpf)
|
|
{
|
|
union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2;
|
|
UInt res, key_size, value_size;
|
|
|
|
PRINT("sys_bpf ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
(Word)ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "bpf",
|
|
int, cmd, union vki_bpf_attr *, attr, unsigned int, size);
|
|
switch (ARG1) {
|
|
case VKI_BPF_PROG_GET_NEXT_ID:
|
|
case VKI_BPF_MAP_GET_NEXT_ID:
|
|
PRE_MEM_WRITE("bpf(attr->next_id", (Addr)&attr->next_id, sizeof(attr->next_id));
|
|
break;
|
|
case VKI_BPF_PROG_GET_FD_BY_ID:
|
|
PRE_MEM_READ("bpf(attr->prog_id", (Addr)&attr->prog_id, sizeof(attr->prog_id));
|
|
break;
|
|
case VKI_BPF_MAP_GET_FD_BY_ID:
|
|
PRE_MEM_READ("bpf(attr->map_id", (Addr)&attr->map_id, sizeof(attr->map_id));
|
|
break;
|
|
case VKI_BPF_BTF_GET_FD_BY_ID:
|
|
PRE_MEM_READ("bpf(attr->btf_id", (Addr)&attr->btf_id, sizeof(attr->btf_id));
|
|
break;
|
|
case VKI_BPF_MAP_CREATE:
|
|
PRE_MEM_READ("bpf(attr->map_flags", (Addr)&attr->map_flags, sizeof(attr->map_flags));
|
|
if (attr->map_flags & VKI_BPF_F_NUMA_NODE)
|
|
PRE_MEM_READ("bpf(attr->numa_node", (Addr)&attr->numa_node, sizeof(attr->numa_node));
|
|
PRE_MEM_READ("bpf(attr->map_type", (Addr)&attr->map_type, sizeof(attr->map_type));
|
|
PRE_MEM_READ("bpf(attr->map_ifindex", (Addr)&attr->map_ifindex, sizeof(attr->map_ifindex));
|
|
PRE_MEM_READ("bpf(attr->max_entries", (Addr)&attr->max_entries, sizeof(attr->max_entries));
|
|
PRE_MEM_READ("bpf(attr->key_size", (Addr)&attr->key_size, sizeof(attr->key_size));
|
|
PRE_MEM_READ("bpf(attr->value_size", (Addr)&attr->value_size, sizeof(attr->value_size));
|
|
pre_asciiz_str(tid, (unsigned long int)attr->map_name,
|
|
VKI_BPF_OBJ_NAME_LEN, "bpf(attr->map_name)");
|
|
switch (attr->map_type) {
|
|
case VKI_BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
|
case VKI_BPF_MAP_TYPE_HASH_OF_MAPS:
|
|
PRE_MEM_READ("bpf(attr->inner_map_fd", (Addr)&attr->inner_map_fd, sizeof(attr->inner_map_fd));
|
|
if (!ML_(fd_allowed)(attr->inner_map_fd, "bpf", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
case VKI_BPF_MAP_TYPE_ARRAY:
|
|
if (ARG3 >= offsetof(union vki_bpf_attr, btf_value_type_id) + sizeof(__vki_u32)) {
|
|
PRE_MEM_READ("bpf(attr->btf_key_type_id", (Addr)&attr->btf_key_type_id, sizeof(attr->btf_key_type_id));
|
|
PRE_MEM_READ("bpf(attr->btf_value_type_id", (Addr)&attr->btf_value_type_id, sizeof(attr->btf_value_type_id));
|
|
if (attr->btf_key_type_id && attr->btf_value_type_id) {
|
|
PRE_MEM_READ("bpf(attr->btf_id", (Addr)&attr->btf_id, sizeof(attr->btf_id));
|
|
if (!ML_(fd_allowed)(attr->btf_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_TYPE_UNSPEC:
|
|
case VKI_BPF_MAP_TYPE_HASH:
|
|
case VKI_BPF_MAP_TYPE_PROG_ARRAY:
|
|
case VKI_BPF_MAP_TYPE_PERF_EVENT_ARRAY:
|
|
case VKI_BPF_MAP_TYPE_PERCPU_HASH:
|
|
case VKI_BPF_MAP_TYPE_PERCPU_ARRAY:
|
|
case VKI_BPF_MAP_TYPE_STACK_TRACE:
|
|
case VKI_BPF_MAP_TYPE_CGROUP_ARRAY:
|
|
case VKI_BPF_MAP_TYPE_LRU_HASH:
|
|
case VKI_BPF_MAP_TYPE_LRU_PERCPU_HASH:
|
|
case VKI_BPF_MAP_TYPE_LPM_TRIE:
|
|
case VKI_BPF_MAP_TYPE_DEVMAP:
|
|
case VKI_BPF_MAP_TYPE_SOCKMAP:
|
|
case VKI_BPF_MAP_TYPE_CPUMAP:
|
|
case VKI_BPF_MAP_TYPE_XSKMAP:
|
|
case VKI_BPF_MAP_TYPE_SOCKHASH:
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_LOOKUP_ELEM:
|
|
/* Perform a lookup on an eBPF map. Read key, write value. */
|
|
PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key));
|
|
PRE_MEM_READ("bpf(attr->value)", (Addr)&attr->value, sizeof(attr->value));
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of key and value for this map. */
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) {
|
|
PRE_MEM_READ("bpf(attr->key)", attr->key, key_size);
|
|
PRE_MEM_WRITE("bpf(attr->value)", attr->value, value_size);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_UPDATE_ELEM:
|
|
/* Add or update a map element in kernel. Read key, read value. */
|
|
PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key));
|
|
PRE_MEM_READ("bpf(attr->value)", (Addr)&attr->value, sizeof(attr->value));
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
PRE_MEM_READ("bpf(attr->flags)", (Addr)&attr->flags, sizeof(attr->flags));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of key and value for this map. */
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) {
|
|
PRE_MEM_READ("bpf(attr->key)", attr->key, key_size);
|
|
PRE_MEM_READ("bpf(attr->value)", attr->value, value_size);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_DELETE_ELEM:
|
|
/* Delete a map element in kernel. Read key from user space. */
|
|
PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key));
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of key for this map. */
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size))
|
|
PRE_MEM_READ("bpf(attr->key)", attr->key, key_size);
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_GET_NEXT_KEY:
|
|
/* From a key, get next key for the map. Read key, write next key. */
|
|
PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key));
|
|
PRE_MEM_READ("bpf(attr->next_key)", (Addr)&attr->next_key, sizeof(attr->next_key));
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
PRE_MEM_READ("bpf(attr->flags)", (Addr)&attr->flags, sizeof(attr->flags));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of key for this map. */
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) {
|
|
PRE_MEM_READ("bpf(attr->key)", attr->key, key_size);
|
|
PRE_MEM_WRITE("bpf(attr->next_key)", attr->next_key, key_size);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_PROG_LOAD:
|
|
/* Load a program into the kernel from an array of instructions. */
|
|
PRE_MEM_READ("bpf(attr->prog_type)", (Addr)&attr->prog_type, sizeof(attr->prog_type));
|
|
PRE_MEM_READ("bpf(attr->prog_flags)", (Addr)&attr->prog_flags, sizeof(attr->prog_flags));
|
|
PRE_MEM_READ("bpf(attr->license)", (Addr)&attr->license, sizeof(attr->license));
|
|
PRE_MEM_READ("bpf(attr->insn_cnt)", (Addr)&attr->insn_cnt, sizeof(attr->insn_cnt));
|
|
PRE_MEM_READ("bpf(attr->expected_attach_type)", (Addr)&attr->expected_attach_type, sizeof(attr->expected_attach_type));
|
|
PRE_MEM_READ("bpf(attr->prog_ifindex)", (Addr)&attr->prog_ifindex, sizeof(attr->prog_ifindex));
|
|
PRE_MEM_READ("bpf(attr->log_level)", (Addr)&attr->log_level, sizeof(attr->log_level));
|
|
PRE_MEM_READ("bpf(attr->log_buf)", (Addr)&attr->log_buf, sizeof(attr->log_buf));
|
|
PRE_MEM_READ("bpf(attr->log_size)", (Addr)&attr->log_size, sizeof(attr->log_size));
|
|
pre_asciiz_str(tid, (Addr)attr->prog_name, VKI_BPF_OBJ_NAME_LEN, "bpf(attr->prog_name)");
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (attr->prog_type == VKI_BPF_PROG_TYPE_KPROBE)
|
|
PRE_MEM_READ("bpf(attr->kern_version)", (Addr)&attr->kern_version, sizeof(attr->kern_version));
|
|
/* Read instructions, license, program name. */
|
|
PRE_MEM_READ("bpf(attr->insns)", attr->insns,
|
|
attr->insn_cnt * sizeof(struct vki_bpf_insn));
|
|
/* License is limited to 128 characters in kernel/bpf/syscall.c. */
|
|
pre_asciiz_str(tid, attr->license, 128, "bpf(attr->license)");
|
|
/* Possibly write up to log_len into user space log buffer. */
|
|
if (attr->log_level || attr->log_size || attr->log_buf)
|
|
PRE_MEM_WRITE("bpf(attr->log_buf)", attr->log_buf, attr->log_size);
|
|
}
|
|
break;
|
|
case VKI_BPF_OBJ_PIN:
|
|
/* Pin eBPF program or map to given location under /sys/fs/bpf/. */
|
|
/* fall through */
|
|
case VKI_BPF_OBJ_GET:
|
|
/* Get pinned eBPF program or map. Read path name. */
|
|
PRE_MEM_READ("bpf(attr->file_flags)", (Addr)&attr->file_flags, sizeof(attr->file_flags));
|
|
PRE_MEM_READ("bpf(attr->pathname)", (Addr)&attr->pathname, sizeof(attr->pathname));
|
|
PRE_MEM_READ("bpf(attr->bpf_fd)", (Addr)&attr->bpf_fd, sizeof(attr->bpf_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->bpf_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
pre_asciiz_str(tid, attr->pathname, VKI_BPF_OBJ_NAME_LEN, "bpf(attr->pathname)");
|
|
}
|
|
break;
|
|
case VKI_BPF_PROG_ATTACH:
|
|
case VKI_BPF_PROG_DETACH:
|
|
/* Detach eBPF program from kernel attach point. */
|
|
PRE_MEM_READ("bpf(attr->attach_type)", (Addr)&attr->attach_type, sizeof(attr->attach_type));
|
|
PRE_MEM_READ("bpf(attr->target_fd)", (Addr)&attr->target_fd, sizeof(attr->target_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
if (ARG1 == VKI_BPF_PROG_ATTACH ||
|
|
(attr->attach_type != VKI_BPF_SK_SKB_STREAM_PARSER &&
|
|
attr->attach_type != VKI_BPF_SK_SKB_STREAM_VERDICT &&
|
|
attr->attach_type != VKI_BPF_SK_MSG_VERDICT)) {
|
|
PRE_MEM_READ("bpf(attr->attach_bpf_fd)", (Addr)&attr->attach_bpf_fd, sizeof(attr->attach_bpf_fd));
|
|
if (!ML_(fd_allowed)(attr->attach_bpf_fd, "bpf", tid, False))
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_PROG_TEST_RUN:
|
|
/* Test prog. Read data_in, write up to data_size_out to data_out. */
|
|
PRE_MEM_READ("bpf(attr->test.prog_fd)", (Addr)&attr->test.prog_fd, sizeof(attr->test.prog_fd));
|
|
PRE_MEM_READ("bpf(attr->test.repeat)", (Addr)&attr->test.repeat, sizeof(attr->test.repeat));
|
|
PRE_MEM_READ("bpf(attr->test.data_size_in)", (Addr)&attr->test.data_size_in, sizeof(attr->test.data_size_in));
|
|
PRE_MEM_READ("bpf(attr->test.data_in)", (Addr)&attr->test.data_in, sizeof(attr->test.data_in));
|
|
PRE_MEM_READ("bpf(attr->test.data_out)", (Addr)&attr->test.data_out, sizeof(attr->test.data_out));
|
|
PRE_MEM_WRITE("bpf(attr->test.retval)", (Addr)&attr->test.retval, sizeof(attr->test.retval));
|
|
PRE_MEM_WRITE("bpf(attr->test.data_size_out)", (Addr)&attr->test.data_size_out, sizeof(attr->test.data_size_out));
|
|
PRE_MEM_WRITE("bpf(attr->test.duration)", (Addr)&attr->test.duration, sizeof(attr->test.duration));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->test.prog_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
PRE_MEM_READ("bpf(attr->test.data_in)", attr->test.data_in, attr->test.data_size_in);
|
|
/* should be data_size_in + VKI_XDP_PACKET_HEADROOM for VKI_BPF_PROG_TYPE_XDP */
|
|
PRE_MEM_WRITE("bpf(attr->test.data_out)", attr->test.data_out, attr->test.data_size_in);
|
|
}
|
|
break;
|
|
case VKI_BPF_OBJ_GET_INFO_BY_FD:
|
|
/* Get info for eBPF map or program. Write info. */
|
|
PRE_MEM_READ("bpf(attr->info.bpf_fd)", (Addr)&attr->info.bpf_fd, sizeof(attr->info.bpf_fd));
|
|
PRE_MEM_READ("bpf(attr->info.info)", (Addr)&attr->info.info, sizeof(attr->info.info));
|
|
PRE_MEM_READ("bpf(attr->info.info_len)", (Addr)&attr->info.info_len, sizeof(attr->info.info_len));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->info.bpf_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of struct to write: is object a program or a map? */
|
|
res = bpf_obj_get_info_size(attr->info.bpf_fd);
|
|
if (res)
|
|
PRE_MEM_WRITE("bpf(attr->info.info)", attr->info.info,
|
|
VG_MIN(attr->info.info_len, res));
|
|
else
|
|
PRE_MEM_WRITE("bpf(attr->info.info)", attr->info.info,
|
|
VG_MIN(attr->info.info_len,
|
|
VG_MAX(VG_MAX(sizeof(struct vki_bpf_prog_info),
|
|
sizeof(struct vki_bpf_map_info)),
|
|
sizeof(struct vki_bpf_btf_info))));
|
|
}
|
|
break;
|
|
case VKI_BPF_PROG_QUERY:
|
|
/*
|
|
* Query list of eBPF program attached to cgroup.
|
|
* Write array of ids (up to attr->query.prog_cnt u32-long ids).
|
|
*/
|
|
PRE_MEM_READ("bpf(attr->query.query_flags)", (Addr)&attr->query.query_flags, sizeof(attr->query.query_flags));
|
|
PRE_MEM_READ("bpf(attr->query.attach_type)", (Addr)&attr->query.attach_type, sizeof(attr->query.attach_type));
|
|
PRE_MEM_READ("bpf(attr->query.target_fd)", (Addr)&attr->query.target_fd, sizeof(attr->query.target_fd));
|
|
PRE_MEM_READ("bpf(attr->query.prog_cnt)", (Addr)&attr->query.prog_cnt, sizeof(attr->query.prog_cnt));
|
|
PRE_MEM_WRITE("bpf(attr->query.attach_flags)", (Addr)&attr->query.attach_flags, sizeof(attr->query.attach_flags));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->query.target_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
if (attr->query.prog_cnt > 0) {
|
|
PRE_MEM_READ("bpf(attr->query.prog_ids)", (Addr)&attr->query.prog_ids, sizeof(attr->query.prog_ids));
|
|
if (attr->query.prog_ids) {
|
|
PRE_MEM_WRITE("bpf(attr->query.prog_ids)", attr->query.prog_ids,
|
|
attr->query.prog_cnt * sizeof(__vki_u32));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_RAW_TRACEPOINT_OPEN:
|
|
/* Open raw tracepoint. Read tracepoint name. */
|
|
PRE_MEM_READ("bpf(attr->raw_tracepoint.name)", (Addr)&attr->raw_tracepoint.name, sizeof(attr->raw_tracepoint.name));
|
|
PRE_MEM_READ("bpf(attr->raw_tracepoint.prog_fd)", (Addr)&attr->raw_tracepoint.prog_fd, sizeof(attr->raw_tracepoint.prog_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->raw_tracepoint.prog_fd,
|
|
"bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Name is limited to 128 characters in kernel/bpf/syscall.c. */
|
|
if (attr->raw_tracepoint.name != 0)
|
|
pre_asciiz_str(tid, attr->raw_tracepoint.name, 128,
|
|
"bpf(attr->raw_tracepoint.name)");
|
|
}
|
|
break;
|
|
case VKI_BPF_BTF_LOAD:
|
|
/* Load BTF information about a program into the kernel. */
|
|
PRE_MEM_READ("bpf(attr->btf)", (Addr)&attr->btf, sizeof(attr->btf));
|
|
PRE_MEM_READ("bpf(attr->btf_size)", (Addr)&attr->btf_size, sizeof(attr->btf_size));
|
|
PRE_MEM_READ("bpf(attr->btf_log_buf)", (Addr)&attr->btf_log_buf, sizeof(attr->btf_log_buf));
|
|
PRE_MEM_READ("bpf(attr->btf_log_size)", (Addr)&attr->btf_log_size, sizeof(attr->btf_log_size));
|
|
PRE_MEM_READ("bpf(attr->btf_log_level)", (Addr)&attr->btf_log_level, sizeof(attr->btf_log_level));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
/* Read BTF data. */
|
|
PRE_MEM_READ("bpf(attr->btf)", attr->btf, attr->btf_size);
|
|
/* Possibly write up to btf_log_len into user space log buffer. */
|
|
if (attr->btf_log_level || attr->btf_log_size || attr->btf_log_buf)
|
|
PRE_MEM_WRITE("bpf(attr->btf_log_buf)",
|
|
attr->btf_log_buf, attr->btf_log_size);
|
|
}
|
|
break;
|
|
case VKI_BPF_TASK_FD_QUERY:
|
|
/* Get info about the task. Write collected info. */
|
|
PRE_MEM_READ("bpf(attr->task_fd_query.pid)", (Addr)&attr->task_fd_query.pid, sizeof(attr->task_fd_query.pid));
|
|
PRE_MEM_READ("bpf(attr->task_fd_query.fd)", (Addr)&attr->task_fd_query.fd, sizeof(attr->task_fd_query.fd));
|
|
PRE_MEM_READ("bpf(attr->task_fd_query.flags)", (Addr)&attr->task_fd_query.flags, sizeof(attr->task_fd_query.flags));
|
|
PRE_MEM_READ("bpf(attr->task_fd_query.buf_len)", (Addr)&attr->task_fd_query.buf_len, sizeof(attr->task_fd_query.buf_len));
|
|
PRE_MEM_READ("bpf(attr->task_fd_query.buf)", (Addr)&attr->task_fd_query.buf, sizeof(attr->task_fd_query.buf));
|
|
PRE_MEM_WRITE("bpf(attr->task_fd_query.prog_id)", (Addr)&attr->task_fd_query.prog_id, sizeof(attr->task_fd_query.prog_id));
|
|
PRE_MEM_WRITE("bpf(attr->task_fd_query.fd_type)", (Addr)&attr->task_fd_query.fd_type, sizeof(attr->task_fd_query.fd_type));
|
|
PRE_MEM_WRITE("bpf(attr->task_fd_query.probe_offset)", (Addr)&attr->task_fd_query.probe_offset, sizeof(attr->task_fd_query.probe_offset));
|
|
PRE_MEM_WRITE("bpf(attr->task_fd_query.probe_addr)", (Addr)&attr->task_fd_query.probe_addr, sizeof(attr->task_fd_query.probe_addr));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->task_fd_query.fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
if (attr->task_fd_query.buf_len > 0) {
|
|
/* Write task or perf event name. */
|
|
PRE_MEM_WRITE("bpf(attr->task_fd_query.buf)",
|
|
attr->task_fd_query.buf,
|
|
attr->task_fd_query.buf_len);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_LOOKUP_AND_DELETE_ELEM:
|
|
/* Perform a lookup on an eBPF map. Read key, write value (delete key) */
|
|
PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key));
|
|
PRE_MEM_READ("bpf(attr->value)", (Addr)&attr->value, sizeof(attr->value));
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
if (ML_(safe_to_deref)(attr, ARG3)) {
|
|
if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) {
|
|
SET_STATUS_Failure(VKI_EBADF);
|
|
break;
|
|
}
|
|
/* Get size of key and value for this map. */
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) {
|
|
PRE_MEM_READ("bpf(attr->key)", attr->key, key_size);
|
|
PRE_MEM_WRITE("bpf(attr->value)", attr->value, value_size);
|
|
}
|
|
}
|
|
break;
|
|
case VKI_BPF_MAP_FREEZE:
|
|
/* Freeze map, read map_fd (write frozen flag, not visible to user space). */
|
|
PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd));
|
|
break;
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,
|
|
"WARNING: unhandled eBPF command %lu\n", ARG1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
POST(sys_bpf)
|
|
{
|
|
union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2;
|
|
UInt key_size, value_size;
|
|
|
|
vg_assert(SUCCESS);
|
|
|
|
switch (ARG1) {
|
|
case VKI_BPF_PROG_GET_NEXT_ID:
|
|
case VKI_BPF_MAP_GET_NEXT_ID:
|
|
POST_MEM_WRITE(attr->next_id, sizeof(attr->next_id));
|
|
break;
|
|
case VKI_BPF_MAP_UPDATE_ELEM:
|
|
case VKI_BPF_MAP_DELETE_ELEM:
|
|
case VKI_BPF_OBJ_PIN:
|
|
case VKI_BPF_PROG_ATTACH:
|
|
case VKI_BPF_PROG_DETACH:
|
|
break;
|
|
/* Following commands have bpf() return a file descriptor. */
|
|
case VKI_BPF_MAP_CREATE:
|
|
case VKI_BPF_OBJ_GET:
|
|
case VKI_BPF_PROG_GET_FD_BY_ID:
|
|
case VKI_BPF_MAP_GET_FD_BY_ID:
|
|
case VKI_BPF_BTF_GET_FD_BY_ID:
|
|
case VKI_BPF_RAW_TRACEPOINT_OPEN:
|
|
if (!ML_(fd_allowed)(RES, "bpf", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure(VKI_EMFILE);
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless)(tid, RES);
|
|
}
|
|
break;
|
|
/*
|
|
* TODO: Is there a way to pass information between PRE and POST hooks?
|
|
* To avoid querying again for the size of keys and values.
|
|
*/
|
|
case VKI_BPF_MAP_LOOKUP_ELEM:
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size))
|
|
POST_MEM_WRITE(attr->value, value_size);
|
|
break;
|
|
case VKI_BPF_MAP_GET_NEXT_KEY:
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size))
|
|
POST_MEM_WRITE(attr->next_key, key_size);
|
|
break;
|
|
case VKI_BPF_PROG_LOAD:
|
|
/* Return a file descriptor for loaded program, write into log_buf. */
|
|
if (!ML_(fd_allowed)(RES, "bpf", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure(VKI_EMFILE);
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless)(tid, RES);
|
|
}
|
|
if (attr->log_level || attr->log_size || attr->log_buf)
|
|
POST_MEM_WRITE(attr->log_buf, attr->log_size);
|
|
break;
|
|
case VKI_BPF_PROG_TEST_RUN:
|
|
POST_MEM_WRITE((Addr)&attr->test.retval, sizeof(attr->test.retval));
|
|
POST_MEM_WRITE((Addr)&attr->test.data_size_out, sizeof(attr->test.data_size_out));
|
|
POST_MEM_WRITE((Addr)&attr->test.duration, sizeof(attr->test.duration));
|
|
POST_MEM_WRITE(attr->test.data_out, attr->test.data_size_out);
|
|
break;
|
|
case VKI_BPF_OBJ_GET_INFO_BY_FD:
|
|
POST_MEM_WRITE(attr->info.info, attr->info.info_len);
|
|
break;
|
|
case VKI_BPF_PROG_QUERY:
|
|
POST_MEM_WRITE((Addr)&attr->query.attach_flags, sizeof(attr->query.attach_flags));
|
|
POST_MEM_WRITE((Addr)&attr->query.prog_cnt, sizeof(attr->query.prog_cnt));
|
|
if (attr->query.prog_ids)
|
|
POST_MEM_WRITE(attr->query.prog_ids,
|
|
attr->query.prog_cnt * sizeof(__vki_u32));
|
|
break;
|
|
case VKI_BPF_BTF_LOAD:
|
|
/* Return a file descriptor for BTF data, write into btf_log_buf. */
|
|
if (!ML_(fd_allowed)(RES, "bpf", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure(VKI_EMFILE);
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless)(tid, RES);
|
|
}
|
|
if (attr->btf_log_level)
|
|
POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size);
|
|
break;
|
|
case VKI_BPF_TASK_FD_QUERY:
|
|
POST_MEM_WRITE(attr->task_fd_query.buf, attr->task_fd_query.buf_len);
|
|
POST_MEM_WRITE((Addr)&attr->task_fd_query.prog_id, sizeof(attr->task_fd_query.prog_id));
|
|
POST_MEM_WRITE((Addr)&attr->task_fd_query.fd_type, sizeof(attr->task_fd_query.fd_type));
|
|
POST_MEM_WRITE((Addr)&attr->task_fd_query.probe_offset, sizeof(attr->task_fd_query.probe_offset));
|
|
POST_MEM_WRITE((Addr)&attr->task_fd_query.probe_addr, sizeof(attr->task_fd_query.probe_addr));
|
|
break;
|
|
case VKI_BPF_MAP_LOOKUP_AND_DELETE_ELEM:
|
|
if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size))
|
|
POST_MEM_WRITE(attr->value, value_size);
|
|
break;
|
|
case VKI_BPF_MAP_FREEZE:
|
|
/* Freeze map, read map_fd (write frozen flag, not visible to user space). */
|
|
break;
|
|
default:
|
|
VG_(message)(Vg_DebugMsg,
|
|
"WARNING: unhandled eBPF command %lu\n", ARG1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
PRE(sys_copy_file_range)
|
|
{
|
|
PRINT("sys_copy_file_range (%lu, %lu, %lu, %lu, %lu, %lu)", ARG1, ARG2, ARG3,
|
|
ARG4, ARG5, ARG6);
|
|
|
|
PRE_REG_READ6(vki_size_t, "copy_file_range",
|
|
int, "fd_in",
|
|
vki_loff_t *, "off_in",
|
|
int, "fd_out",
|
|
vki_loff_t *, "off_out",
|
|
vki_size_t, "len",
|
|
unsigned int, "flags");
|
|
|
|
/* File descriptors are "specially" tracked by valgrind.
|
|
valgrind itself uses some, so make sure someone didn't
|
|
put in one of our own... */
|
|
if (!ML_(fd_allowed)(ARG1, "copy_file_range(fd_in)", tid, False) ||
|
|
!ML_(fd_allowed)(ARG3, "copy_file_range(fd_in)", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
} else {
|
|
/* Now see if the offsets are defined. PRE_MEM_READ will
|
|
double check it can dereference them. */
|
|
if (ARG2 != 0)
|
|
PRE_MEM_READ( "copy_file_range(off_in)", ARG2, sizeof(vki_loff_t));
|
|
if (ARG4 != 0)
|
|
PRE_MEM_READ( "copy_file_range(off_out)", ARG4, sizeof(vki_loff_t));
|
|
}
|
|
}
|
|
|
|
PRE(sys_pkey_alloc)
|
|
{
|
|
PRINT("pkey_alloc (%lu, %lu)", ARG1, ARG2);
|
|
|
|
PRE_REG_READ2(long, "pkey_alloc",
|
|
unsigned long, "flags",
|
|
unsigned long, "access_rights");
|
|
|
|
/* The kernel says: pkey_alloc() is always safe to call regardless of
|
|
whether or not the operating system supports protection keys. It can be
|
|
used in lieu of any other mechanism for detecting pkey support and will
|
|
simply fail with the error ENOSPC if the operating system has no pkey
|
|
support.
|
|
|
|
So we simply always return ENOSPC to signal memory protection keys are
|
|
not supported under valgrind, unless there are unknown flags, then we
|
|
return EINVAL. */
|
|
unsigned long pkey_flags = ARG1;
|
|
if (pkey_flags != 0)
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
else
|
|
SET_STATUS_Failure( VKI_ENOSPC );
|
|
}
|
|
|
|
PRE(sys_pkey_free)
|
|
{
|
|
PRINT("pkey_free (%" FMT_REGWORD "u )", ARG1);
|
|
|
|
PRE_REG_READ1(long, "pkey_free",
|
|
unsigned long, "pkey");
|
|
|
|
/* Since pkey_alloc () can never succeed, see above, freeing any pkey is
|
|
always an error. */
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
|
|
PRE(sys_pkey_mprotect)
|
|
{
|
|
PRINT("sys_pkey_mprotect ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "pkey_mprotect",
|
|
unsigned long, addr, vki_size_t, len, unsigned long, prot,
|
|
unsigned long, pkey);
|
|
|
|
Addr addr = ARG1;
|
|
SizeT len = ARG2;
|
|
Int prot = ARG3;
|
|
Int pkey = ARG4;
|
|
|
|
/* Since pkey_alloc () can never succeed, see above, any pkey is
|
|
invalid. Except for -1, then pkey_mprotect acts just like mprotect. */
|
|
if (pkey != -1)
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
else
|
|
handle_sys_mprotect (tid, status, &addr, &len, &prot);
|
|
|
|
ARG1 = addr;
|
|
ARG2 = len;
|
|
ARG3 = prot;
|
|
}
|
|
|
|
POST(sys_pkey_mprotect)
|
|
{
|
|
Addr addr = ARG1;
|
|
SizeT len = ARG2;
|
|
Int prot = ARG3;
|
|
|
|
ML_(notify_core_and_tool_of_mprotect)(addr, len, prot);
|
|
}
|
|
|
|
PRE(sys_io_uring_setup)
|
|
{
|
|
PRINT("sys_io_uring_setup ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
|
|
ARG1, ARG2);
|
|
PRE_REG_READ2(long, "io_uring_setup", unsigned int, entries,
|
|
struct vki_io_uring_params *, p);
|
|
if (ARG2)
|
|
PRE_MEM_READ("io_uring_setup(p)", ARG2,
|
|
offsetof(struct vki_io_uring_params, sq_off));
|
|
}
|
|
|
|
POST(sys_io_uring_setup)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "io_uring_setup", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless)(tid, RES);
|
|
POST_MEM_WRITE(ARG2 + offsetof(struct vki_io_uring_params, sq_off),
|
|
sizeof(struct vki_io_sqring_offsets) +
|
|
sizeof(struct vki_io_cqring_offsets));
|
|
}
|
|
}
|
|
|
|
PRE(sys_io_uring_enter)
|
|
{
|
|
PRINT("sys_io_uring_enter ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u %" FMT_REGWORD "u, %" FMT_REGWORD "u %"
|
|
FMT_REGWORD "u )",
|
|
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
|
PRE_REG_READ6(long, "io_uring_enter",
|
|
unsigned int, fd, unsigned int, to_submit,
|
|
unsigned int, min_complete, unsigned int, flags,
|
|
const void *, sig, unsigned long, sigsz);
|
|
if (ARG5)
|
|
PRE_MEM_READ("io_uring_enter(sig)", ARG5, ARG6);
|
|
}
|
|
|
|
POST(sys_io_uring_enter)
|
|
{
|
|
}
|
|
|
|
PRE(sys_io_uring_register)
|
|
{
|
|
PRINT("sys_io_uring_register ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
|
|
PRE_REG_READ4(long, "io_uring_register",
|
|
unsigned int, fd, unsigned int, opcode,
|
|
void *, arg, unsigned int, nr_args);
|
|
switch (ARG2) {
|
|
case VKI_IORING_REGISTER_BUFFERS:
|
|
PRE_MEM_READ("", ARG3, ARG4 * sizeof(struct vki_iovec));
|
|
break;
|
|
case VKI_IORING_UNREGISTER_BUFFERS:
|
|
break;
|
|
case VKI_IORING_REGISTER_FILES:
|
|
PRE_MEM_READ("", ARG3, ARG4 * sizeof(__vki_s32));
|
|
break;
|
|
case VKI_IORING_UNREGISTER_FILES:
|
|
break;
|
|
case VKI_IORING_REGISTER_EVENTFD:
|
|
PRE_MEM_READ("", ARG3, sizeof(__vki_s32));
|
|
break;
|
|
case VKI_IORING_UNREGISTER_EVENTFD:
|
|
break;
|
|
}
|
|
}
|
|
|
|
POST(sys_io_uring_register)
|
|
{
|
|
}
|
|
|
|
PRE(sys_execveat)
|
|
{
|
|
PRINT("sys_execveat ( %lu, %#lx(%s), %#lx, %#lx, %lu", ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5);
|
|
PRE_REG_READ5(vki_off_t, "execveat",
|
|
int, fd, char *, filename, char **, argv, char **, envp, int, flags);
|
|
PRE_MEM_RASCIIZ( "execveat(filename)", ARG2);
|
|
|
|
#if !defined(__NR_execveat)
|
|
SET_STATUS_Failure(VKI_ENOSYS);
|
|
return;
|
|
#endif
|
|
|
|
const HChar *path = (const HChar*) ARG2;
|
|
Addr arg_2 = ARG3;
|
|
Addr arg_3 = ARG4;
|
|
const HChar *buf;
|
|
HChar *abs_path = NULL;
|
|
Bool check_at_symlink = False;
|
|
Bool check_pathptr = True;
|
|
|
|
if (ML_(safe_to_deref) (path, 1)) {
|
|
/* If pathname is absolute, we'll ignore dirfd
|
|
* and just pass the pathname, try to determine
|
|
* the absolute path otherwise. */
|
|
if (path[0] != '/') {
|
|
/* Check dirfd is a valid fd. */
|
|
if (!ML_(fd_allowed)(ARG1, "execveat", tid, False)) {
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
return;
|
|
}
|
|
/* If pathname is empty and AT_EMPTY_PATH is
|
|
set then dirfd describes the whole path. */
|
|
if (path[0] == '\0') {
|
|
if (ARG5 & VKI_AT_EMPTY_PATH) {
|
|
if (VG_(resolve_filename)(ARG1, &buf)) {
|
|
path = buf;
|
|
check_pathptr = False;
|
|
}
|
|
}
|
|
}
|
|
else if (ARG1 == VKI_AT_FDCWD) {
|
|
check_at_symlink = True;
|
|
} else
|
|
if (ARG5 & VKI_AT_SYMLINK_NOFOLLOW)
|
|
check_at_symlink = True;
|
|
else if (VG_(resolve_filename)(ARG1, &buf)) {
|
|
abs_path = VG_(malloc)("execveat",
|
|
(VG_(strlen)(buf) + 1
|
|
+ VG_(strlen)(path) + 1));
|
|
VG_(sprintf)(abs_path, "%s/%s", buf, path);
|
|
path = abs_path;
|
|
check_pathptr = False;
|
|
}
|
|
else
|
|
path = NULL;
|
|
if (check_at_symlink) {
|
|
struct vg_stat statbuf;
|
|
SysRes statres;
|
|
|
|
statres = VG_(stat)(path, &statbuf);
|
|
if (sr_isError(statres) || VKI_S_ISLNK(statbuf.mode)) {
|
|
SET_STATUS_Failure( VKI_ELOOP );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SET_STATUS_Failure(VKI_EFAULT);
|
|
return;
|
|
}
|
|
|
|
handle_pre_sys_execve(tid, status, (Addr) path, arg_2, arg_3, EXECVEAT,
|
|
check_pathptr);
|
|
|
|
/* The exec failed, we keep running... cleanup. */
|
|
VG_(free)(abs_path);
|
|
|
|
|
|
}
|
|
|
|
PRE(sys_close_range)
|
|
{
|
|
SysRes res = VG_(mk_SysRes_Success)(0);
|
|
unsigned int beg, end;
|
|
unsigned int last = ARG2;
|
|
|
|
FUSE_COMPATIBLE_MAY_BLOCK();
|
|
PRINT("sys_close_range ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %"
|
|
FMT_REGWORD "u )", ARG1, ARG2, ARG3);
|
|
PRE_REG_READ3(long, "close_range",
|
|
unsigned int, first, unsigned int, last,
|
|
unsigned int, flags);
|
|
|
|
if (ARG1 > last) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
return;
|
|
}
|
|
|
|
if (last >= VG_(fd_hard_limit))
|
|
last = VG_(fd_hard_limit) - 1;
|
|
|
|
if (ARG1 > last) {
|
|
SET_STATUS_Success ( 0 );
|
|
return;
|
|
}
|
|
|
|
beg = end = ARG1;
|
|
do {
|
|
if (end > last
|
|
|| (end == 2/*stderr*/ && VG_(debugLog_getLevel)() > 0)
|
|
|| end == VG_(log_output_sink).fd
|
|
|| end == VG_(xml_output_sink).fd) {
|
|
/* Split the range if it contains a file descriptor we're not
|
|
* supposed to close. */
|
|
if (end - 1 >= beg)
|
|
res = VG_(do_syscall3)(__NR_close_range, (UWord)beg, (UWord)end - 1, ARG3 );
|
|
beg = end + 1;
|
|
}
|
|
} while (end++ <= last);
|
|
|
|
/* If it failed along the way, it's presumably the flags being wrong. */
|
|
SET_STATUS_from_SysRes (res);
|
|
}
|
|
|
|
POST(sys_close_range)
|
|
{
|
|
unsigned int fd;
|
|
unsigned int last = ARG2;
|
|
|
|
if (!VG_(clo_track_fds)
|
|
|| (ARG3 & VKI_CLOSE_RANGE_CLOEXEC) != 0)
|
|
return;
|
|
|
|
if (last >= VG_(fd_hard_limit))
|
|
last = VG_(fd_hard_limit) - 1;
|
|
|
|
for (fd = ARG1; fd <= last; fd++)
|
|
if ((fd != 2/*stderr*/ || VG_(debugLog_getLevel)() == 0)
|
|
&& fd != VG_(log_output_sink).fd
|
|
&& fd != VG_(xml_output_sink).fd)
|
|
ML_(record_fd_close)(fd);
|
|
}
|
|
|
|
|
|
#define VKI_O_DIRECTORY 00200000
|
|
#define VKI___O_TMPFILE 020000000
|
|
#define VKI_O_TMPFILE (VKI___O_TMPFILE | VKI_O_DIRECTORY)
|
|
|
|
// long syscall(SYS_openat2, int dirfd, const char *pathname,
|
|
// struct open_how *how, size_t size);
|
|
PRE(sys_openat2)
|
|
{
|
|
HChar name[30]; // large enough
|
|
SysRes sres;
|
|
struct vki_open_how * how;
|
|
|
|
PRINT("sys_openat2 ( %ld, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %ld )",
|
|
SARG1, ARG2, (HChar*)(Addr)ARG2, ARG3, SARG4);
|
|
PRE_REG_READ4(long, "openat2",
|
|
int, dfd, const char *, filename, struct vki_open_how *, how, vki_size_t, size);
|
|
|
|
PRE_MEM_RASCIIZ( "openat2(filename)", ARG2 );
|
|
PRE_MEM_READ( "openat2(how)", ARG3, sizeof(struct vki_open_how));
|
|
|
|
/* For absolute filenames, dfd is ignored. If dfd is AT_FDCWD,
|
|
filename is relative to cwd. When comparing dfd against AT_FDCWD,
|
|
be sure only to compare the bottom 32 bits. */
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& *(Char *)(Addr)ARG2 != '/'
|
|
&& ((Int)ARG1) != ((Int)VKI_AT_FDCWD)
|
|
&& !ML_(fd_allowed)(ARG1, "openat2", tid, False))
|
|
SET_STATUS_Failure( VKI_EBADF );
|
|
|
|
how = (struct vki_open_how *)ARG3;
|
|
|
|
if (how && ML_(safe_to_deref) (how, sizeof(struct vki_open_how))) {
|
|
if (how->vki_mode) {
|
|
if (!(how->vki_flags & ((vki_uint64_t)VKI_O_CREAT | VKI_O_TMPFILE))) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
}
|
|
if (how->vki_resolve & ~((vki_uint64_t)VKI_RESOLVE_NO_XDEV |
|
|
VKI_RESOLVE_NO_MAGICLINKS |
|
|
VKI_RESOLVE_NO_SYMLINKS |
|
|
VKI_RESOLVE_BENEATH |
|
|
VKI_RESOLVE_IN_ROOT |
|
|
VKI_RESOLVE_CACHED)) {
|
|
SET_STATUS_Failure( VKI_EINVAL );
|
|
}
|
|
}
|
|
|
|
/* Handle the case where the open is of /proc/self/cmdline or
|
|
/proc/<pid>/cmdline, and just give it a copy of the fd for the
|
|
fake file we cooked up at startup (in m_main). Also, seek the
|
|
cloned fd back to the start. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/cmdline", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/cmdline") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_cmdline_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Do the same for /proc/self/auxv or /proc/<pid>/auxv case. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/auxv") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_auxv_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* And for /proc/self/exe or /proc/<pid>/exe case. */
|
|
|
|
VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
|
|
if (ML_(safe_to_deref)( (void*)(Addr)ARG2, 1 )
|
|
&& (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0
|
|
|| VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/exe") == 0)) {
|
|
sres = VG_(dup)( VG_(cl_exec_fd) );
|
|
SET_STATUS_from_SysRes( sres );
|
|
if (!sr_isError(sres)) {
|
|
OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
|
|
if (off < 0)
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Otherwise handle normally */
|
|
*flags |= SfMayBlock;
|
|
}
|
|
|
|
POST(sys_openat2)
|
|
{
|
|
vg_assert(SUCCESS);
|
|
if (!ML_(fd_allowed)(RES, "openat2", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)(Addr)ARG2);
|
|
}
|
|
}
|
|
|
|
PRE(sys_pidfd_open)
|
|
{
|
|
PRINT("sys_pidfd_open ( %ld, %lu )", SARG1, ARG2);
|
|
}
|
|
|
|
POST(sys_pidfd_open)
|
|
{
|
|
if (!ML_(fd_allowed)(RES, "pidfd", tid, True)) {
|
|
VG_(close)(RES);
|
|
SET_STATUS_Failure( VKI_EMFILE );
|
|
} else {
|
|
if (VG_(clo_track_fds))
|
|
ML_(record_fd_open_nameless) (tid, RES);
|
|
}
|
|
}
|
|
|
|
#undef PRE
|
|
#undef POST
|
|
|
|
#endif // defined(VGO_linux)
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|