From: Christian B. <bor...@de...> - 2010-12-16 13:47:22
|
This patch implements client and host system calls for s390x. --- coregrind/m_syscall.c | 63 + coregrind/m_syswrap/syscall-s390x-linux.S | 172 +++ coregrind/m_syswrap/syswrap-generic.c | 5 coregrind/m_syswrap/syswrap-linux.c | 19 coregrind/m_syswrap/syswrap-main.c | 79 + coregrind/m_syswrap/syswrap-s390x-linux.c | 1524 ++++++++++++++++++++++++++++++ coregrind/pub_core_syscall.h | 1 7 files changed, 1855 insertions(+), 8 deletions(-) --- valgrind-upstream.orig/coregrind/m_syscall.c +++ valgrind-upstream/coregrind/m_syscall.c @@ -100,6 +100,17 @@ SysRes VG_(mk_SysRes_ppc64_linux) ( ULon return res; } +SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) { + SysRes res; + res._isError = val >= -4095 && val <= -1; + if (res._isError) { + res._val = -val; + } else { + res._val = val; + } + return res; +} + SysRes VG_(mk_SysRes_arm_linux) ( Int val ) { SysRes res; res._isError = val >= -4095 && val <= -1; @@ -719,6 +730,40 @@ asm(".private_extern _do_syscall_mach_WR " retq \n" ); +#elif defined(VGP_s390x_linux) + +#define _svc_clobber "1", "cc", "memory" + +static UWord do_syscall_WRK ( + UWord syscall_no, + UWord arg1, UWord arg2, UWord arg3, + UWord arg4, UWord arg5, UWord arg6 + ) +{ + register UWord __arg1 asm("2") = arg1; + register UWord __arg2 asm("3") = arg2; + register UWord __arg3 asm("4") = arg3; + register UWord __arg4 asm("5") = arg4; + register UWord __arg5 asm("6") = arg5; + register UWord __arg6 asm("7") = arg6; + register ULong __svcres asm("2"); + + __asm__ __volatile__ ( + "lgr %%r1,%1\n\t" + "svc 0\n\t" + : "=d" (__svcres) + : "a" (syscall_no), + "0" (__arg1), + "d" (__arg2), + "d" (__arg3), + "d" (__arg4), + "d" (__arg5), + "d" (__arg6) + : _svc_clobber); + + return (UWord) (__svcres); +} + #else # error Unknown platform #endif @@ -846,6 +891,24 @@ SysRes VG_(do_syscall) ( UWord sysno, UW } return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO ); +#elif defined(VGP_s390x_linux) + UWord val; + + if (sysno == __NR_mmap) { + ULong argbuf[6]; + + argbuf[0] = a1; + argbuf[1] = a2; + argbuf[2] = a3; + argbuf[3] = a4; + argbuf[4] = a5; + argbuf[5] = a6; + val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0); + } else { + val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6); + } + + return VG_(mk_SysRes_s390x_linux)( val ); #else # error Unknown platform #endif --- /dev/null +++ valgrind-upstream/coregrind/m_syswrap/syscall-s390x-linux.S @@ -0,0 +1,172 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-s390x-linux.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright IBM Corp. 2010 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* Contributed by Christian Borntraeger */ + +#include "pub_core_basics_asm.h" +#include "pub_core_vkiscnums_asm.h" +#include "libvex_guest_offsets.h" + +#if defined(VGA_s390x) + +/*----------------------------------------------------------------*/ +/* + Perform a syscall for the client. This will run a syscall + with the client's specific per-thread signal mask. + + The structure of this function is such that, if the syscall is + interrupted by a signal, we can determine exactly what + execution state we were in with respect to the execution of + the syscall by examining the value of NIP in the signal + handler. This means that we can always do the appropriate + thing to precisely emulate the kernel's signal/syscall + interactions. + + The syscall number is taken from the argument, since the syscall + number can be encoded in the svc instruction itself. + The syscall result is written back to guest register r2. + + Returns 0 if the syscall was successfully called (even if the + syscall itself failed), or a nonzero error code in the lowest + 8 bits if one of the sigprocmasks failed (there's no way to + determine which one failed). And there's no obvious way to + recover from that either, but nevertheless we want to know. + + VG_(fixup_guest_state_after_syscall_interrupted) does the + thread state fixup in the case where we were interrupted by a + signal. + + Prototype: + + UWord ML_(do_syscall_for_client_WRK)( + Int syscallno, // r2 + void* guest_state, // r3 + const vki_sigset_t *sysmask, // r4 + const vki_sigset_t *postmask, // r5 + Int nsigwords) // r6 +*/ +/* from vki_arch.h */ +#define VKI_SIG_SETMASK 2 + +#define SP_SAVE 16 +#define SP_R2 SP_SAVE + 0*8 +#define SP_R3 SP_SAVE + 1*8 +#define SP_R4 SP_SAVE + 2*8 +#define SP_R5 SP_SAVE + 3*8 +#define SP_R6 SP_SAVE + 4*8 +#define SP_R7 SP_SAVE + 5*8 +#define SP_R8 SP_SAVE + 6*8 +#define SP_R9 SP_SAVE + 7*8 + +.align 4 +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): +1: /* Even though we can't take a signal until the sigprocmask completes, + start the range early. + If eip is in the range [1,2), the syscall hasn't been started yet */ + + /* Set the signal mask which should be current during the syscall. */ + /* Save and restore all the parameters and all the registers that + we clobber (r6-r9) */ + stmg %r2,%r9, SP_R2(%r15) + + lghi %r2, VKI_SIG_SETMASK /* how */ + lgr %r3, %r4 /* sysmask */ + lgr %r4, %r5 /* postmask */ + lgr %r5, %r6 /* nsigwords */ + svc __NR_rt_sigprocmask + cghi %r2, 0x0 + jne 7f /* sigprocmask failed */ + + /* OK, that worked. Now do the syscall proper. */ + lg %r9, SP_R3(%r15) /* guest state --> r9 */ + lg %r2, OFFSET_s390x_r2(%r9) /* guest r2 --> real r2 */ + lg %r3, OFFSET_s390x_r3(%r9) /* guest r3 --> real r3 */ + lg %r4, OFFSET_s390x_r4(%r9) /* guest r4 --> real r4 */ + lg %r5, OFFSET_s390x_r5(%r9) /* guest r5 --> real r5 */ + lg %r6, OFFSET_s390x_r6(%r9) /* guest r6 --> real r6 */ + lg %r7, OFFSET_s390x_r7(%r9) /* guest r7 --> real r7 */ + lg %r1, SP_R2(%r15) /* syscallno -> r1 */ + +2: svc 0 + +3: + stg %r2, OFFSET_s390x_r2(%r9) + +4: /* Re-block signals. If eip is in [4,5), then the syscall + is complete and we needn't worry about it. */ + lghi %r2, VKI_SIG_SETMASK /* how */ + lg %r3, SP_R5(%r15) /* postmask */ + lghi %r4, 0x0 /* NULL */ + lg %r5, SP_R6(%r15) /* nsigwords */ + svc __NR_rt_sigprocmask + cghi %r2, 0x0 + jne 7f /* sigprocmask failed */ + +5: /* everyting ok. return 0 and restore the call-saved + registers, that we have clobbered */ + lghi %r2, 0x0 + lmg %r6,%r9, SP_R6(%r15) + br %r14 + +7: /* some problem. return 0x8000 | error and restore the call-saved + registers we have clobbered. */ + nill %r2, 0x7fff + oill %r2, 0x8000 + lmg %r6,%r9, SP_R6(%r15) + br %r14 + +.section .rodata +/* export the ranges so that + VG_(fixup_guest_state_after_syscall_interrupted) can do the + right thing */ + +.globl ML_(blksys_setup) +.globl ML_(blksys_restart) +.globl ML_(blksys_complete) +.globl ML_(blksys_committed) +.globl ML_(blksys_finished) + +/* the compiler can assume that 8 byte data elements are aligned on 8 byte */ +.align 8 +ML_(blksys_setup): .quad 1b +ML_(blksys_restart): .quad 2b +ML_(blksys_complete): .quad 3b +ML_(blksys_committed): .quad 4b +ML_(blksys_finished): .quad 5b +.previous + +/* Let the linker know we don't need an executable stack */ +.section .note.GNU-stack,"",@progbits + +#endif /* VGA_s390x */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ --- valgrind-upstream.orig/coregrind/m_syswrap/syswrap-generic.c +++ valgrind-upstream/coregrind/m_syswrap/syswrap-generic.c @@ -1958,6 +1958,11 @@ ML_(generic_POST_sys_shmctl) ( ThreadId * call, mmap (aka sys_mmap) which takes the arguments in the * normal way and the offset in bytes. * + * - On s390x-linux there is mmap (aka old_mmap) which takes the + * arguments in a memory block and the offset in bytes. mmap2 + * is also available (but not exported via unistd.h) with + * arguments ina memory block and the offset in pages. + * * To cope with all this we provide a generic handler function here * and then each platform implements one or more system call handlers * which call this generic routine after extracting and normalising --- valgrind-upstream.orig/coregrind/m_syswrap/syswrap-linux.c +++ valgrind-upstream/coregrind/m_syswrap/syswrap-linux.c @@ -206,6 +206,14 @@ static void run_a_thread_NORETURN ( Word "svc 0x00000000\n" /* exit(tst->os_state.exitcode) */ : "=m" (tst->status) : "r" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); +#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"); #else # error Unknown platform #endif @@ -288,6 +296,11 @@ void VG_(main_thread_wrapper_NORETURN)(T 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. @@ -342,6 +355,10 @@ SysRes ML_(do_fork_clone) ( ThreadId tid 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 first the stack and then the flags */ + res = VG_(do_syscall4)( __NR_clone, (UWord) NULL, flags, + (UWord)parent_tidptr, (UWord)child_tidptr); #else # error Unknown platform #endif @@ -3566,7 +3583,7 @@ POST(sys_lookup_dcookie) } #endif -#if defined(VGP_amd64_linux) +#if defined(VGP_amd64_linux) || defined(VGP_s390x_linux) PRE(sys_lookup_dcookie) { *flags |= SfMayBlock; --- valgrind-upstream.orig/coregrind/m_syswrap/syswrap-main.c +++ valgrind-upstream/coregrind/m_syswrap/syswrap-main.c @@ -60,14 +60,14 @@ /* Useful info which needs to be recorded somewhere: Use of registers in syscalls is: - NUM ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 ARG8 RESULT + NUM ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 ARG8 RESULT LINUX: - x86 eax ebx ecx edx esi edi ebp n/a n/a eax (== NUM) - amd64 rax rdi rsi rdx r10 r8 r9 n/a n/a rax (== NUM) - ppc32 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1) - ppc64 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1) - arm r7 r0 r1 r2 r3 r4 r5 n/a n/a r0 (== ARG1) - + x86 eax ebx ecx edx esi edi ebp n/a n/a eax (== NUM) + amd64 rax rdi rsi rdx r10 r8 r9 n/a n/a rax (== NUM) + ppc32 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1) + ppc64 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1) + arm r7 r0 r1 r2 r3 r4 r5 n/a n/a r0 (== ARG1) + s390x SYSNO r2 r3 r4 r5 r6 r7 n/a n/a r2 (== ARG1) AIX: ppc32 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err) ppc64 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err) @@ -160,6 +160,9 @@ x86: Success(N) ==> edx:eax = N, cc = 0 Fail(N) ==> edx:eax = N, cc = 1 + s390x: Success(N) ==> r2 = N + Fail(N) ==> r2 = -N + * The post wrapper is called if: - it exists, and @@ -611,6 +614,17 @@ void getSyscallArgsFromGuestState ( /*OU // no canonical->sysno adjustment needed +#elif defined(VGP_s390x_linux) + VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla; + canonical->sysno = gst->guest_SYSNO; + canonical->arg1 = gst->guest_r2; + canonical->arg2 = gst->guest_r3; + canonical->arg3 = gst->guest_r4; + canonical->arg4 = gst->guest_r5; + canonical->arg5 = gst->guest_r6; + canonical->arg6 = gst->guest_r7; + canonical->arg7 = 0; + canonical->arg8 = 0; #else # error "getSyscallArgsFromGuestState: unknown arch" #endif @@ -728,6 +742,16 @@ void putSyscallArgsIntoGuestState ( /*IN stack[1] = canonical->arg7; stack[2] = canonical->arg8; +#elif defined(VGP_s390x_linux) + VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla; + gst->guest_SYSNO = canonical->sysno; + gst->guest_r2 = canonical->arg1; + gst->guest_r3 = canonical->arg2; + gst->guest_r4 = canonical->arg3; + gst->guest_r5 = canonical->arg4; + gst->guest_r6 = canonical->arg5; + gst->guest_r7 = canonical->arg6; + #else # error "putSyscallArgsIntoGuestState: unknown arch" #endif @@ -842,6 +866,11 @@ void getSyscallStatusFromGuestState ( /* ); canonical->what = SsComplete; +# elif defined(VGP_s390x_linux) + VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla; + canonical->sres = VG_(mk_SysRes_s390x_linux)( gst->guest_r2 ); + canonical->what = SsComplete; + # else # error "getSyscallStatusFromGuestState: unknown arch" # endif @@ -1016,6 +1045,15 @@ void putSyscallStatusIntoGuestState ( /* break; } +# elif defined(VGP_s390x_linux) + VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla; + vg_assert(canonical->what == SsComplete); + if (sr_isError(canonical->sres)) { + gst->guest_r2 = - (Long)sr_Err(canonical->sres); + } else { + gst->guest_r2 = sr_Res(canonical->sres); + } + # else # error "putSyscallStatusIntoGuestState: unknown arch" # endif @@ -1129,6 +1167,16 @@ void getSyscallArgLayout ( /*OUT*/Syscal layout->s_arg7 = sizeof(UWord) * 1; layout->s_arg8 = sizeof(UWord) * 2; +#elif defined(VGP_s390x_linux) + layout->o_sysno = OFFSET_s390x_SYSNO; + layout->o_arg1 = OFFSET_s390x_r2; + layout->o_arg2 = OFFSET_s390x_r3; + layout->o_arg3 = OFFSET_s390x_r4; + layout->o_arg4 = OFFSET_s390x_r5; + layout->o_arg5 = OFFSET_s390x_r6; + layout->o_arg6 = OFFSET_s390x_r7; + layout->uu_arg7 = -1; /* impossible value */ + layout->uu_arg8 = -1; /* impossible value */ #else # error "getSyscallLayout: unknown arch" #endif @@ -1957,6 +2005,23 @@ void ML_(fixup_guest_state_to_restart_sy // DDD: #warning GrP fixme amd64 restart unimplemented vg_assert(0); +#elif defined(VGP_s390x_linux) + arch->vex.guest_IA -= 2; // sizeof(syscall) + + /* Make sure our caller is actually sane, and we're really backing + back over a syscall. + + syscall == 0A <num> + */ + { + UChar *p = (UChar *)arch->vex.guest_IA; + if (p[0] != 0x0A) + VG_(message)(Vg_DebugMsg, + "?! restarting over syscall at %#llx %02x %02x\n", + arch->vex.guest_IA, p[0], p[1]); + + vg_assert(p[0] == 0x0A); + } #else # error "ML_(fixup_guest_state_to_restart_syscall): unknown plat" #endif --- /dev/null +++ valgrind-upstream/coregrind/m_syswrap/syswrap-s390x-linux.c @@ -0,0 +1,1524 @@ + +/*--------------------------------------------------------------------*/ +/*--- Platform-specific syscalls stuff. syswrap-s390x-linux.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright IBM Corp. 2010 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* Contributed by Christian Borntraeger */ + +#if defined(VGP_s390x_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_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_mallocfree.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)() +#include "pub_core_signals.h" +#include "pub_core_syscall.h" +#include "pub_core_syswrap.h" +#include "pub_core_tooliface.h" +#include "pub_core_stacks.h" // VG_(register_stack) + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ +#include "priv_syswrap-linux.h" /* for decls of linux-ish wrappers */ +#include "priv_syswrap-linux-variants.h" /* decls of linux variant wrappers */ +#include "priv_syswrap-main.h" + + +/* --------------------------------------------------------------------- + clone() handling + ------------------------------------------------------------------ */ + +/* Call f(arg1), but first switch stacks, using 'stack' as the new + stack, and use 'retaddr' as f's return-to address. Also, clear all + the integer registers before entering f. + Thought: Why are we clearing the GPRs ? The callee pointed to by f + is a regular C function which will play by the ABI rules. So there is + no need to zero out the GPRs. If we assumed that f accesses registers at + will, then it would make sense to create a defined register state. + But then, why only for the GPRs and not the FPRs ? */ +__attribute__((noreturn)) +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); +/* Upon entering this function we have the following setup: + r2 = stack + r3 = retaddr + r4 = f_desc + r5 = arg1 +*/ +asm( + ".text\n" + ".align 4\n" + ".globl vgModuleLocal_call_on_new_stack_0_1\n" + ".type vgModuleLocal_call_on_new_stack_0_1, @function\n" + "vgModuleLocal_call_on_new_stack_0_1:\n" + " lgr %r15,%r2\n" // stack to r15 + " lgr %r14,%r3\n" // retaddr to r14 + " lgr %r2,%r5\n" // arg1 to r2 + // zero all gprs to get a defined state + " lghi %r0,0\n" + " lghi %r1,0\n" + // r2 holds the argument for the callee + " lghi %r3,0\n" + // r4 holds the callee address + " lghi %r5,0\n" + " lghi %r6,0\n" + " lghi %r7,0\n" + " lghi %r8,0\n" + " lghi %r9,0\n" + " lghi %r10,0\n" + " lghi %r11,0\n" + " lghi %r12,0\n" + " lghi %r13,0\n" + // r14 holds the return address for the callee + // r15 is the stack pointer + " br %r4\n" // jump to f + ".previous\n" + ); + +/* + Perform a clone system call. clone is strange because it has + fork()-like return-twice semantics, so it needs special + handling here. + + Upon entry, we have: + void* child_stack in r2 + long flags in r3 + int* parent_tid in r4 + int* child_tid in r5 + int* child_tid in r6 + Word (*fn)(void *) 160(r15) + void *arg 168(r15) + + System call requires: + void* child_stack in r2 (sc arg1) + long flags in r3 (sc arg2) + int* parent_tid in r4 (sc arg3) + int* child_tid in r5 (sc arg4) + void* tlsaddr in r6 (sc arg5) + + Returns a ULong encoded as: top half is %cr following syscall, + low half is syscall return value (r3). + */ +#define __NR_CLONE VG_STRINGIFY(__NR_clone) +#define __NR_EXIT VG_STRINGIFY(__NR_exit) + +extern +ULong do_syscall_clone_s390x_linux ( void *stack, + ULong flags, + Int *child_tid, + Int *parent_tid, + Addr tlsaddr, + Word (*fn)(void *), + void *arg); +asm( + " .text\n" + " .align 4\n" + "do_syscall_clone_s390x_linux:\n" + " lg %r1, 160(%r15)\n" // save fn from parent stack into r1 + " lg %r0, 168(%r15)\n" // save arg from parent stack into r0 + " aghi %r2, -160\n" // create stack frame for child + // all syscall parameters are already in place (r2-r6) + " svc " __NR_CLONE"\n" // clone() + " ltgr %r2,%r2\n" // child if retval == 0 + " jne 1f\n" + + // CHILD - call thread function + " lgr %r2, %r0\n" // get arg from r0 + " basr %r14,%r1\n" // call fn + + // exit. The result is already in r2 + " svc " __NR_EXIT"\n" + + // Exit returned?! + " j +2\n" + + "1:\n" // PARENT or ERROR + " br %r14\n" + ".previous\n" +); + +#undef __NR_CLONE +#undef __NR_EXIT + +void VG_(cleanup_thread) ( ThreadArchState* arch ) +{ + /* only used on x86 for descriptor tables */ +} + +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; +} + + +/* + When a client clones, we need to keep track of the new thread. This means: + 1. allocate a ThreadId+ThreadState+stack for the 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 IP, and a separate stack + for SP. + */ +static SysRes do_clone ( ThreadId ptid, + Addr sp, ULong flags, + Int *parent_tidptr, + Int *child_tidptr, + Addr tlsaddr) +{ + static const Bool debug = False; + + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(ptid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + UWord* stack; + NSegment const* seg; + SysRes res; + ULong r2; + 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 ); + + /* Make sys_clone appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_r2 = 0; + + if (sp != 0) + ctst->arch.vex.guest_r15 = sp; + + ctst->os_state.parent = ptid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* have the parents thread group */ + ctst->os_state.threadgroup = ptst->os_state.threadgroup; + + /* We don't really know where the client stack is, because its + allocated by the client. The best we can do is look at the + memory mappings and try to derive some useful information. We + assume that esp starts near its highest possible value, and can + only go down to the start of the mmaped segment. */ + seg = VG_(am_find_nsegment)((Addr)sp); + if (seg && seg->kind != SkResvn) { + ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(sp); + ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start; + + VG_(register_stack)(seg->start, ctst->client_stack_highest_word); + + if (debug) + VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n", + ctid, seg->start, VG_PGROUNDUP(sp)); + } else { + VG_(message)(Vg_UserMsg, + "!? New thread %d starts with SP(%#lx) unmapped\n", + ctid, sp); + ctst->client_stack_szB = 0; + } + + /* Assume the clone will succeed, and tell any tool that wants to + know that this thread has come into existence. If the clone + fails, we'll send out a ll_exit notification for it at the out: + label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, ptid, ctid ); + + if (flags & VKI_CLONE_SETTLS) { + if (debug) + VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr); + ctst->arch.vex.guest_a0 = (UInt) (tlsaddr >> 32); + ctst->arch.vex.guest_a1 = (UInt) tlsaddr; + } + flags &= ~VKI_CLONE_SETTLS; + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Create the new thread */ + r2 = do_syscall_clone_s390x_linux( + stack, flags, child_tidptr, parent_tidptr, tlsaddr, + ML_(start_thread_NORETURN), &VG_(threads)[ctid]); + + res = VG_(mk_SysRes_s390x_linux)( r2 ); + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + + out: + if (sr_isError(res)) { + /* clone failed */ + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } + + return res; + +} + + + +/* --------------------------------------------------------------------- + PRE/POST wrappers for s390x/Linux-specific syscalls + ------------------------------------------------------------------ */ + +#define PRE(name) DEFN_PRE_TEMPLATE(s390x_linux, name) +#define POST(name) DEFN_POST_TEMPLATE(s390x_linux, name) + +/* Add prototypes for the wrappers declared here, so that gcc doesn't + harass us for not having prototypes. Really this is a kludge -- + the right thing to do is to make these wrappers 'static' since they + aren't visible outside this file, but that requires even more macro + magic. */ + +DECL_TEMPLATE(s390x_linux, sys_ptrace); +DECL_TEMPLATE(s390x_linux, sys_socketcall); +DECL_TEMPLATE(s390x_linux, sys_mmap); +DECL_TEMPLATE(s390x_linux, sys_ipc); +DECL_TEMPLATE(s390x_linux, sys_clone); +DECL_TEMPLATE(s390x_linux, sys_sigreturn); +DECL_TEMPLATE(s390x_linux, sys_rt_sigreturn); +DECL_TEMPLATE(s390x_linux, sys_fadvise64); + +// PEEK TEXT,DATA and USER are common to all architectures +// PEEKUSR_AREA and POKEUSR_AREA are special, having a memory area +// containing the real addr, data, and len field pointed to by ARG3 +// instead of ARG4 +PRE(sys_ptrace) +{ + PRINT("sys_ptrace ( %ld, %ld, %#lx, %#lx )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "ptrace", + long, request, long, pid, long, addr, long, data); + switch (ARG1) { + case VKI_PTRACE_PEEKTEXT: + case VKI_PTRACE_PEEKDATA: + case VKI_PTRACE_PEEKUSR: + PRE_MEM_WRITE( "ptrace(peek)", ARG4, + sizeof (long)); + break; + case VKI_PTRACE_GETEVENTMSG: + PRE_MEM_WRITE( "ptrace(geteventmsg)", ARG4, sizeof(unsigned long)); + break; + case VKI_PTRACE_GETSIGINFO: + PRE_MEM_WRITE( "ptrace(getsiginfo)", ARG4, sizeof(vki_siginfo_t)); + break; + case VKI_PTRACE_SETSIGINFO: + PRE_MEM_READ( "ptrace(setsiginfo)", ARG4, sizeof(vki_siginfo_t)); + break; + case VKI_PTRACE_PEEKUSR_AREA: + { + vki_ptrace_area *pa; + + /* Reads a part of the user area into the memory at pa->process_addr */ + pa = (vki_ptrace_area *) ARG3; + PRE_MEM_READ("ptrace(peekusrarea ptrace_area->len)", + (unsigned long) &pa->vki_len, sizeof(pa->vki_len)); + PRE_MEM_READ("ptrace(peekusrarea ptrace_area->kernel_addr)", + (unsigned long) &pa->vki_kernel_addr, sizeof(pa->vki_kernel_addr)); + PRE_MEM_READ("ptrace(peekusrarea ptrace_area->process_addr)", + (unsigned long) &pa->vki_process_addr, sizeof(pa->vki_process_addr)); + PRE_MEM_WRITE("ptrace(peekusrarea *(ptrace_area->process_addr))", + pa->vki_process_addr, pa->vki_len); + break; + } + case VKI_PTRACE_POKEUSR_AREA: + { + vki_ptrace_area *pa; + + /* Updates a part of the user area from the memory at pa->process_addr */ + pa = (vki_ptrace_area *) ARG3; + PRE_MEM_READ("ptrace(pokeusrarea ptrace_area->len)", + (unsigned long) &pa->vki_len, sizeof(pa->vki_len)); + PRE_MEM_READ("ptrace(pokeusrarea ptrace_area->kernel_addr)", + (unsigned long) &pa->vki_kernel_addr, sizeof(pa->vki_kernel_addr)); + PRE_MEM_READ("ptrace(pokeusrarea ptrace_area->process_addr)", + (unsigned long) &pa->vki_process_addr, sizeof(pa->vki_process_addr)); + PRE_MEM_READ("ptrace(pokeusrarea *(ptrace_area->process_addr))", + pa->vki_process_addr, pa->vki_len); + break; + } + default: + break; + } +} + +POST(sys_ptrace) +{ + switch (ARG1) { + case VKI_PTRACE_PEEKTEXT: + case VKI_PTRACE_PEEKDATA: + case VKI_PTRACE_PEEKUSR: + POST_MEM_WRITE( ARG4, sizeof (long)); + break; + case VKI_PTRACE_GETEVENTMSG: + POST_MEM_WRITE( ARG4, sizeof(unsigned long)); + break; + case VKI_PTRACE_GETSIGINFO: + /* XXX: This is a simplification. Different parts of the + * siginfo_t are valid depending on the type of signal. + */ + POST_MEM_WRITE( ARG4, sizeof(vki_siginfo_t)); + break; + case VKI_PTRACE_PEEKUSR_AREA: + { + vki_ptrace_area *pa; + + pa = (vki_ptrace_area *) ARG3; + POST_MEM_WRITE(pa->vki_process_addr, pa->vki_len); + } + default: + break; + } +} + + +PRE(sys_socketcall) +{ +# define ARG2_0 (((UWord*)ARG2)[0]) +# define ARG2_1 (((UWord*)ARG2)[1]) +# define ARG2_2 (((UWord*)ARG2)[2]) +# define ARG2_3 (((UWord*)ARG2)[3]) +# define ARG2_4 (((UWord*)ARG2)[4]) +# define ARG2_5 (((UWord*)ARG2)[5]) + + *flags |= SfMayBlock; + PRINT("sys_socketcall ( %ld, %#lx )",ARG1,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( "socketcall.socketpair(args)", ARG2, 4*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 4*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.socket(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + break; + + case VKI_SYS_BIND: + /* int bind(int sockfd, struct sockaddr *my_addr, + int addrlen); */ + PRE_MEM_READ( "socketcall.bind(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.listen(args)", ARG2, 2*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 2*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + break; + + case VKI_SYS_ACCEPT: { + /* int accept(int s, struct sockaddr *addr, int *addrlen); */ + PRE_MEM_READ( "socketcall.accept(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.sendto(args)", ARG2, 6*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 6*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.send(args)", ARG2, 4*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 4*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.recvfrom(args)", ARG2, 6*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 6*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.recv(args)", ARG2, 4*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 4*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.connect(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.setsockopt(args)", ARG2, 5*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 5*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + ML_(generic_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( "socketcall.getsockopt(args)", ARG2, 5*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 5*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.getsockname(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.getpeername(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + 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( "socketcall.shutdown(args)", ARG2, 2*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 2*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + break; + + case VKI_SYS_SENDMSG: { + /* int sendmsg(int s, const struct msghdr *msg, int flags); */ + PRE_MEM_READ( "socketcall.sendmsg(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + ML_(generic_PRE_sys_sendmsg)( tid, ARG2_0, ARG2_1 ); + break; + } + + case VKI_SYS_RECVMSG: { + /* int recvmsg(int s, struct msghdr *msg, int flags); */ + PRE_MEM_READ("socketcall.recvmsg(args)", ARG2, 3*sizeof(Addr) ); + if (!ML_(valid_client_addr)(ARG2, 3*sizeof(Addr), tid, NULL)) { + SET_STATUS_Failure( VKI_EFAULT ); + break; + } + ML_(generic_PRE_sys_recvmsg)( tid, ARG2_0, ARG2_1 ); + 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*)ARG2)[0]) +# define ARG2_1 (((UWord*)ARG2)[1]) +# define ARG2_2 (((UWord*)ARG2)[2]) +# define ARG2_3 (((UWord*)ARG2)[3]) +# define ARG2_4 (((UWord*)ARG2)[4]) +# define ARG2_5 (((UWord*)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: + /* int accept(int s, struct sockaddr *addr, int *addrlen); */ + 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, ARG2_0, ARG2_1 ); + 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 +} + +PRE(sys_mmap) +{ + UWord a0, a1, a2, a3, a4, a5; + SysRes r; + + UWord* args = (UWord*)ARG1; + PRE_REG_READ1(long, "sys_mmap", struct mmap_arg_struct *, args); + PRE_MEM_READ( "sys_mmap(args)", (Addr) args, 6*sizeof(UWord) ); + + a0 = args[0]; + a1 = args[1]; + a2 = args[2]; + a3 = args[3]; + a4 = args[4]; + a5 = args[5]; + + PRINT("sys_mmap ( %#lx, %llu, %ld, %ld, %ld, %ld )", + a0, (ULong)a1, a2, a3, a4, a5 ); + + r = ML_(generic_PRE_sys_mmap)( tid, a0, a1, a2, a3, a4, (Off64T)a5 ); + SET_STATUS_from_SysRes(r); +} + +static Addr deref_Addr ( ThreadId tid, Addr a, Char* s ) +{ + Addr* a_p = (Addr*)a; + PRE_MEM_READ( s, (Addr)a_p, sizeof(Addr) ); + return *a_p; +} + +PRE(sys_ipc) +{ + PRINT("sys_ipc ( %ld, %ld, %ld, %ld, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + // XXX: this is simplistic -- some args are not used in all circumstances. + PRE_REG_READ6(int, "ipc", + vki_uint, call, int, first, int, second, int, third, + void *, ptr, long, fifth) + + switch (ARG1 /* call */) { + case VKI_SEMOP: + ML_(generic_PRE_sys_semop)( tid, ARG2, ARG5, ARG3 ); + *flags |= SfMayBlock; + break; + case VKI_SEMGET: + break; + case VKI_SEMCTL: + { + UWord arg = deref_Addr( tid, ARG5, "semctl(arg)" ); + ML_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg ); + break; + } + case VKI_SEMTIMEDOP: + ML_(generic_PRE_sys_semtimedop)( tid, ARG2, ARG5, ARG3, ARG6 ); + *flags |= SfMayBlock; + break; + case VKI_MSGSND: + ML_(linux_PRE_sys_msgsnd)( tid, ARG2, ARG5, ARG3, ARG4 ); + if ((ARG4 & VKI_IPC_NOWAIT) == 0) + *flags |= SfMayBlock; + break; + case VKI_MSGRCV: + { + Addr msgp; + Word msgtyp; + + msgp = deref_Addr( tid, + (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp), + "msgrcv(msgp)" ); + msgtyp = deref_Addr( tid, + (Addr) (&((struct vki_ipc_kludge *)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: + break; + case VKI_MSGCTL: + ML_(linux_PRE_sys_msgctl)( tid, ARG2, ARG3, ARG5 ); + break; + case VKI_SHMAT: + { + 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: + if (!ML_(generic_PRE_sys_shmdt)(tid, ARG5)) + SET_STATUS_Failure( VKI_EINVAL ); + break; + case VKI_SHMGET: + break; + case VKI_SHMCTL: /* IPCOP_shmctl */ + ML_(generic_PRE_sys_shmctl)( tid, ARG2, ARG3, ARG5 ); + break; + default: + VG_(message)(Vg_DebugMsg, "FATAL: unhandled syscall(ipc) %ld", 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 = deref_Addr( tid, ARG5, "semctl(arg)" ); + ML_(generic_PRE_sys_semctl)( tid, 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 *)ARG5)->msgp), + "msgrcv(msgp)" ); + msgtyp = deref_Addr( tid, + (Addr) (&((struct vki_ipc_kludge *)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) %ld", + ARG1 ); + VG_(core_panic)("... bye!\n"); + break; /*NOTREACHED*/ + } +} + +PRE(sys_clone) +{ + UInt cloneflags; + + PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4, ARG5); + PRE_REG_READ4(int, "clone", + void *, child_stack, + unsigned long, flags, + int *, parent_tidptr, + int *, child_tidptr); + + if (ARG2 & VKI_CLONE_PARENT_SETTID) { + PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int)); + if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), + VKI_PROT_WRITE)) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + } + if (ARG2 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) { + PRE_MEM_WRITE("clone(child_tidptr)", ARG4, sizeof(Int)); + if (!VG_(am_is_valid_for_client)(ARG4, sizeof(Int), + VKI_PROT_WRITE)) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + } + + cloneflags = ARG2; + + if (!ML_(client_signal_OK)(ARG2 & 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, + (Addr)ARG1, /* child SP */ + ARG2, /* flags */ + (Int *)ARG3, /* parent_tidptr */ + (Int *)ARG4, /* child_tidptr */ + (Addr)ARG5)); /* tlsaddr */ + break; + + case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */ + /* FALLTHROUGH - assume vfork == fork */ + cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM); + + case 0: /* plain fork */ + SET_STATUS_from_SysRes( + ML_(do_fork_clone)(tid, + cloneflags, /* flags */ + (Int *)ARG3, /* parent_tidptr */ + (Int *)ARG4)); /* child_tidptr */ + break; + + default: + /* should we just ENOSYS? */ + VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx", ARG2); + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "The only supported clone() uses are:"); + VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)"); + VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork"); + VG_(unimplemented) + ("Valgrind does not support general clone()."); + } + + if (SUCCESS) { + if (ARG2 & VKI_CLONE_PARENT_SETTID) + POST_MEM_WRITE(ARG3, sizeof(Int)); + if (ARG2 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) + POST_MEM_WRITE(ARG4, sizeof(Int)); + + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } +} + +PRE(sys_sigreturn) +{ + ThreadState* tst; + PRINT("sys_sigreturn ( )"); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + tst = VG_(get_ThreadState)(tid); + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + /* Restore register state from frame and remove it */ + VG_(sigframe_destroy)(tid, False); + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + + +PRE(sys_rt_sigreturn) +{ + /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for + an explanation of what follows. */ + + ThreadState* tst; + PRINT("sys_rt_sigreturn ( )"); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + tst = VG_(get_ThreadState)(tid); + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + /* Restore register state from frame and remove it */ + VG_(sigframe_destroy)(tid, True); + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +/* we cant use the LINX_ version for 64 bit */ +PRE(sys_fadvise64) +{ + PRINT("sys_fadvise64 ( %ld, %ld, %ld, %ld )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "fadvise64", + int, fd, vki_loff_t, offset, vki_loff_t, len, int, advice); +} + +#undef PRE +#undef POST + +/* --------------------------------------------------------------------- + The s390x/Linux syscall table + ------------------------------------------------------------------ */ + +/* Add an s390x-linux specific wrapper to a syscall table. */ +#define PLAX_(sysno, name) WRAPPER_ENTRY_X_(s390x_linux, sysno, name) +#define PLAXY(sysno, name) WRAPPER_ENTRY_XY(s390x_linux, sysno, name) + +// This table maps from __NR_xxx syscall numbers from +// linux/arch/s390/kernel/syscalls.S to the appropriate PRE/POST sys_foo() +// wrappers on s390x. There are several unused numbers, which are only +// defined on s390 (31bit mode) but no longer available on s390x (64 bit). +// For those syscalls not handled by Valgrind, the annotation indicate its +// arch/OS combination, eg. */* (generic), */Linux (Linux only), ?/? +// (unknown). + +static SyscallTableEntry syscall_table[] = { + GENX_(0, sys_ni_syscall), /* unimplemented (by the kernel) */ // 0 + GENX_(__NR_exit, sys_exit), // 1 + GENX_(__NR_fork, sys_fork), // 2 + GENXY(__NR_read, sys_read), // 3 + GENX_(__NR_write, sys_write), // 4 + + GENXY(__NR_open, sys_open), // 5 + GENXY(__NR_close, sys_close), // 6 +// ?????(__NR_restart_syscall, ), // 7 + GENXY(__NR_creat, sys_creat), // 8 + GENX_(__NR_link, sys_link), // 9 + + GENX_(__NR_unlink, sys_unlink), // 10 + GENX_(__NR_execve, sys_execve), // 11 + GENX_(__NR_chdir, sys_chdir), // 12 + GENX_(13, sys_ni_syscall), /* unimplemented (by the kernel) */ // 13 + GENX_(__NR_mknod, sys_mknod), // 14 + + GENX_(__NR_chmod, sys_chmod), // 15 + GENX_(16, sys_ni_syscall), /* unimplemented (by the kernel) */ // 16 + GENX_(17, sys_ni_syscall), /* unimplemented (by the kernel) */ // 17 + GENX_(18, sys_ni_syscall), /* unimplemented (by the kernel) */ // 18 + LINX_(__NR_lseek, sys_lseek), // 19 + + GENX_(__NR_getpid, sys_getpid), // 20 + LINX_(__NR_mount, sys_mount), // 21 + LINX_(__NR_umount, sys_oldumount), // 22 + GENX_(23, sys_ni_syscall), /* unimplemented (by the kernel) */ // 23 + GENX_(24, sys_ni_syscall), /* unimplemented (by the kernel) */ // 24 + + GENX_(25, sys_ni_syscall), /* unimplemented (by the kernel) */ // 25 + PLAXY(__NR_ptrace, sys_ptrace), // 26 + GENX_(__NR_alarm, sys_alarm), // 27 + GENX_(28, sys_ni_syscall), /* unimplemented (by the kernel) */ // 28 + GENX_(__NR_pause, sys_pause), // 29 + + LINX_(__NR_utime, sys_utime), // 30 + GENX_(31, sys_ni_syscall), /* unimplemented (by the kernel) */ // 31 + GENX_(32, sys_ni_syscall), /* unimplemented (by the kernel) */ // 32 + GENX_(__NR_access, sys_access), // 33 + GENX_(__NR_nice, sys_nice), // 34 + + GENX_(35, sys_ni_syscall), /* unimplemented (by the kernel) */ // 35 + GENX_(__NR_sync, sys_sync), // 36 + GENX_(__NR_kill, sys_kill), // 37 + GENX_(__NR_rename, sys_rename), // 38 + GENX_(__NR_mkdir, sys_mkdir), // 39 + + GENX_(__NR_rmdir, sys_rmdir), // 40 + GENXY(__NR_dup, sys_dup), // 41 + LINXY(__NR_pipe, sys_pipe), // 42 + GENXY(__NR_times, sys_times), // 43 + GENX_(44, sys_ni_syscall), /* unimplemented (by the kernel) */ // 44 + + GENX_(__NR_brk, sys_brk), // 45 + GENX_(46, sys_ni_syscall), /* unimplemented (by the kernel) */ // 46 + GENX_(47, sys_ni_syscall), /* unimplemented (by the kernel) */ // 47 +// ?????(__NR_signal, ), // 48 + GENX_(49, sys_ni_syscall), /* unimplemented (by the kernel) */ // 49 + + GENX_(50, sys_ni_syscall), /* unimplemented (by the kernel) */ // 50 + GENX_(__NR_acct, sys_acct), // 51 + LINX_(__NR_umount2, sys_umount), // 52 + GENX_(53, sys_ni_syscall), /* unimplemented (by the kernel) */ // 53 + LINXY(__NR_ioctl, sys_ioctl), // 54 + + LINXY(__NR_fcntl, sys_fcntl), // 55 + GENX_(56, sys_ni_syscall), /* unimplemented (by the kernel) */ // 56 + GENX_(__NR_setpgid, sys_setpgid), // 57 + GENX_(58, sys_ni_syscall), /* unimplemented (by the kernel) */ // 58 + GENX_(59, sys_ni_syscall), /* unimplemented (by the kernel) */ // 59 + + GENX_(__NR_umask, sys_umask), // 60 + GENX_(__NR_chroot, sys_chroot), // 61 +// ?????(__NR_ustat, sys_ustat), /* deprecated in favor of statfs */ // 62 + GENXY(__NR_dup2, sys_dup2), // 63 + GENX_(__NR_getppid, sys_getppid), // 64 + + GENX_(__NR_getpgrp, sys_getpgrp), // 65 + GENX_(__NR_setsid, sys_setsid), // 66 +// ?????(__NR_sigaction, ), /* userspace uses rt_sigaction */ // 67 + GENX_(68, sys_ni_syscall), /* unimplemented (by the kernel) */ // 68 + GENX_(69, sys_ni_syscall), /* unimplemented (by the kernel) */ // 69 + + GENX_(70, sys_ni_syscall), /* unimplemented (by the kernel) */ // 70 + GENX_(71, sys_ni_syscall), /* unimplemented (by the kernel) */ // 71 +// ?????(__NR_sigsuspend, ), // 72 +// ?????(__NR_sigpending, ), // 73 +// ?????(__NR_sethostname, ), // 74 + + GENX_(__NR_setrlimit, sys_setrlimit), // 75 + GENXY(76, sys_getrlimit), /* see also 191 */ // 76 + GENXY(__NR_getrusage, sys_getrusage), // 77 + GENXY(__NR_gettimeofday, sys_gettimeofday), // 78 + GENX_(__NR_settimeofday, sys_settimeofday), // 79 + + GENX_(80, sys_ni_syscall), /* unimplemented (by the kernel) */ // 80 + GENX_(81, sys_ni_syscall), /* unimplemented (by the kernel) */ // 81 + GENX_(82, sys_ni_syscall), /* unimplemented (by the kernel) */ // 82 + GENX_(__NR_symlink, sys_symlink), // 83 + GENX_(84, sys_ni_syscall), /* unimplemented (by the kernel) */ // 84 + + GENX_(__NR_readlink, sys_readlink), // 85 +// ?????(__NR_uselib, ), // 86 +// ?????(__NR_swapon, ), // 87 +// ?????(__NR_reboot, ), // 88 + GENX_(89, sys_ni_syscall), /* unimplemented (by the kernel) */ // 89 + + PLAX_(__NR_mmap, sys_mmap ), // 90 + GENXY(__NR_munmap, sys_munmap), // 91 + GENX_(__NR_truncate, sys_truncate), // 92 + GENX_(__NR_ftruncate, sys_ftruncate), // 93 + GENX_(__NR_fchmod, sys_fchmod), // 94 + + GENX_(95, sys_ni_syscall), /* unimplemented (by the kernel) */ // 95 + GENX_(__NR_getpriority, sys_getpriority), // 96 + GENX_(__NR_setpriority, sys_setpriority), // 97 + GENX_(98, sys_ni_syscall), /* unimplemented (by the kernel) */ // 98 + GENXY(__NR_statfs, sys_statfs), // 99 + + GENXY(__NR_fstatfs, sys_fstatfs), // 100 + GENX_(101, sys_ni_syscall), /* unimplemented (by the kernel) */ // 101 + PLAXY(__NR_socketcall, sys_socketcall), // 102 + LINXY(__NR_syslog, sys_syslog), // 103 + GENXY(__NR_setitimer, sys_setitimer), // 104 + + GENXY(__NR_getitimer, sys_getitimer), ... [truncated message content] |