Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Doing syscalls.                                  m_syscall.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2011 Julian Seward
     11       jseward (at) acm.org
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     26    02111-1307, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 #include "pub_core_basics.h"
     32 #include "pub_core_libcassert.h"
     33 #include "pub_core_vki.h"
     34 #include "pub_core_vkiscnums.h"
     35 #include "pub_core_syscall.h"
     36 
     37 /* ---------------------------------------------------------------------
     38    Building syscall return values.
     39    ------------------------------------------------------------------ */
     40 
     41 #if defined(VGO_linux)
     42 
     43 /* Make a SysRes value from a syscall return value.  This is
     44    Linux-specific.
     45 
     46    From:
     47    http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/
     48    linux/i386/sysdep.h?
     49    rev=1.28&content-type=text/x-cvsweb-markup&cvsroot=glibc
     50 
     51    Linux uses a negative return value to indicate syscall errors,
     52    unlike most Unices, which use the condition codes' carry flag.
     53 
     54    Since version 2.1 the return value of a system call might be
     55    negative even if the call succeeded.  E.g., the 'lseek' system call
     56    might return a large offset.  Therefore we must not anymore test
     57    for < 0, but test for a real error by making sure the value in %eax
     58    is a real error number.  Linus said he will make sure the no
     59    syscall returns a value in -1 .. -4095 as a valid result so we can
     60    safely test with -4095.
     61 */
     62 
     63 SysRes VG_(mk_SysRes_x86_linux) ( Int val ) {
     64    SysRes res;
     65    res._isError = val >= -4095 && val <= -1;
     66    if (res._isError) {
     67       res._val = (UInt)(-val);
     68    } else {
     69       res._val = (UInt)val;
     70    }
     71    return res;
     72 }
     73 
     74 /* Similarly .. */
     75 SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
     76    SysRes res;
     77    res._isError = val >= -4095 && val <= -1;
     78    if (res._isError) {
     79       res._val = (ULong)(-val);
     80    } else {
     81       res._val = (ULong)val;
     82    }
     83    return res;
     84 }
     85 
     86 /* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speak) */
     87 /* Note this must be in the bottom bit of the second arg */
     88 SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
     89    SysRes res;
     90    res._isError = (cr0so & 1) != 0;
     91    res._val     = val;
     92    return res;
     93 }
     94 
     95 /* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
     96 SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
     97    SysRes res;
     98    res._isError = (cr0so & 1) != 0;
     99    res._val     = val;
    100    return res;
    101 }
    102 
    103 SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
    104    SysRes res;
    105    res._isError = val >= -4095 && val <= -1;
    106    if (res._isError) {
    107       res._val = -val;
    108    } else {
    109       res._val = val;
    110    }
    111    return res;
    112 }
    113 
    114 SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
    115    SysRes res;
    116    res._isError = val >= -4095 && val <= -1;
    117    if (res._isError) {
    118       res._val = (UInt)(-val);
    119    } else {
    120       res._val = (UInt)val;
    121    }
    122    return res;
    123 }
    124 
    125 /* Generic constructors. */
    126 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    127    SysRes r;
    128    r._isError = True;
    129    r._val     = err;
    130    return r;
    131 }
    132 
    133 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    134    SysRes r;
    135    r._isError = False;
    136    r._val     = res;
    137    return r;
    138 }
    139 
    140 
    141 #elif defined(VGO_darwin)
    142 
    143 /* Darwin: Some syscalls return a double-word result. */
    144 SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
    145                                    UInt wHI, UInt wLO )
    146 {
    147    SysRes res;
    148    res._wHI  = 0;
    149    res._wLO  = 0;
    150    res._mode = 0; /* invalid */
    151    vg_assert(isErr == False || isErr == True);
    152    vg_assert(sizeof(UWord) == sizeof(UInt));
    153    switch (scclass) {
    154       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    155          res._wLO  = wLO;
    156          res._wHI  = wHI;
    157          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    158          break;
    159       case VG_DARWIN_SYSCALL_CLASS_MACH:
    160          vg_assert(!isErr);
    161          vg_assert(wHI == 0);
    162          res._wLO  = wLO;
    163          res._mode = SysRes_MACH;
    164          break;
    165       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    166          vg_assert(!isErr);
    167          vg_assert(wHI == 0);
    168          res._wLO  = wLO;
    169          res._mode = SysRes_MDEP;
    170          break;
    171       default:
    172          vg_assert(0);
    173    }
    174    return res;
    175 }
    176 
    177 SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
    178                                      ULong wHI, ULong wLO )
    179 {
    180    SysRes res;
    181    res._wHI  = 0;
    182    res._wLO  = 0;
    183    res._mode = 0; /* invalid */
    184    vg_assert(isErr == False || isErr == True);
    185    vg_assert(sizeof(UWord) == sizeof(ULong));
    186    switch (scclass) {
    187       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    188          res._wLO  = wLO;
    189          res._wHI  = wHI;
    190          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    191          break;
    192       case VG_DARWIN_SYSCALL_CLASS_MACH:
    193          vg_assert(!isErr);
    194          vg_assert(wHI == 0);
    195          res._wLO  = wLO;
    196          res._mode = SysRes_MACH;
    197          break;
    198       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    199          vg_assert(!isErr);
    200          vg_assert(wHI == 0);
    201          res._wLO  = wLO;
    202          res._mode = SysRes_MDEP;
    203          break;
    204       default:
    205          vg_assert(0);
    206    }
    207    return res;
    208 }
    209 
    210 /* Generic constructors.  We assume (without checking if this makes
    211    any sense, from the caller's point of view) that these are for the
    212    UNIX style of syscall. */
    213 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    214    SysRes r;
    215    r._wHI  = 0;
    216    r._wLO  = err;
    217    r._mode = SysRes_UNIX_ERR;
    218    return r;
    219 }
    220 
    221 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    222    SysRes r;
    223    r._wHI  = 0;
    224    r._wLO  = res;
    225    r._mode = SysRes_UNIX_OK;
    226    return r;
    227 }
    228 
    229 
    230 #else
    231 #  error "Unknown OS"
    232 #endif
    233 
    234 
    235 /* ---------------------------------------------------------------------
    236    VG_(do_syscall): A function for doing syscalls.
    237    ------------------------------------------------------------------ */
    238 
    239 #if defined(VGP_x86_linux)
    240 /* Incoming args (syscall number + up to 6 args) come on the stack.
    241    (ie. the C calling convention).
    242 
    243    The syscall number goes in %eax.  The args are passed to the syscall in
    244    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
    245    calling convention.
    246 
    247    %eax gets the return value.  Not sure which registers the kernel
    248    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
    249    %ebp).
    250 */
    251 extern UWord do_syscall_WRK (
    252           UWord syscall_no,
    253           UWord a1, UWord a2, UWord a3,
    254           UWord a4, UWord a5, UWord a6
    255        );
    256 asm(
    257 ".text\n"
    258 "do_syscall_WRK:\n"
    259 "	push	%esi\n"
    260 "	push	%edi\n"
    261 "	push	%ebx\n"
    262 "	push	%ebp\n"
    263 "	movl	16+ 4(%esp),%eax\n"
    264 "	movl	16+ 8(%esp),%ebx\n"
    265 "	movl	16+12(%esp),%ecx\n"
    266 "	movl	16+16(%esp),%edx\n"
    267 "	movl	16+20(%esp),%esi\n"
    268 "	movl	16+24(%esp),%edi\n"
    269 "	movl	16+28(%esp),%ebp\n"
    270 "	int	$0x80\n"
    271 "	popl	%ebp\n"
    272 "	popl	%ebx\n"
    273 "	popl	%edi\n"
    274 "	popl	%esi\n"
    275 "	ret\n"
    276 ".previous\n"
    277 );
    278 
    279 #elif defined(VGP_amd64_linux)
    280 /* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
    281    %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
    282    calling convention).
    283 
    284    The syscall number goes in %rax.  The args are passed to the syscall in
    285    the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
    286    ie. the kernel's syscall calling convention.
    287 
    288    %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
    289    no matter, they are caller-save (the syscall clobbers no callee-save
    290    regs, so we don't have to do any register saving/restoring).
    291 */
    292 extern UWord do_syscall_WRK (
    293           UWord syscall_no,
    294           UWord a1, UWord a2, UWord a3,
    295           UWord a4, UWord a5, UWord a6
    296        );
    297 asm(
    298 ".text\n"
    299 "do_syscall_WRK:\n"
    300         /* Convert function calling convention --> syscall calling
    301            convention */
    302 "	movq	%rdi, %rax\n"
    303 "	movq	%rsi, %rdi\n"
    304 "	movq	%rdx, %rsi\n"
    305 "	movq	%rcx, %rdx\n"
    306 "	movq	%r8,  %r10\n"
    307 "	movq	%r9,  %r8\n"
    308 "	movq    8(%rsp), %r9\n"	 /* last arg from stack */
    309 "	syscall\n"
    310 "	ret\n"
    311 ".previous\n"
    312 );
    313 
    314 #elif defined(VGP_ppc32_linux)
    315 /* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
    316 
    317    The syscall number goes in %r0.  The args are passed to the syscall in
    318    the regs %r3:%r8, i.e. the kernel's syscall calling convention.
    319 
    320    The %cr0.so bit flags an error.
    321    We return the syscall return value in %r3, and the %cr0.so in
    322    the lowest bit of %r4.
    323    We return a ULong, of which %r3 is the high word, and %r4 the low.
    324    No callee-save regs are clobbered, so no saving/restoring is needed.
    325 */
    326 extern ULong do_syscall_WRK (
    327           UWord syscall_no,
    328           UWord a1, UWord a2, UWord a3,
    329           UWord a4, UWord a5, UWord a6
    330        );
    331 asm(
    332 ".text\n"
    333 "do_syscall_WRK:\n"
    334 "        mr      0,3\n"
    335 "        mr      3,4\n"
    336 "        mr      4,5\n"
    337 "        mr      5,6\n"
    338 "        mr      6,7\n"
    339 "        mr      7,8\n"
    340 "        mr      8,9\n"
    341 "        sc\n"                  /* syscall: sets %cr0.so on error         */
    342 "        mfcr    4\n"           /* %cr -> low word of return var          */
    343 "        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
    344 "        blr\n"                 /* and return                             */
    345 ".previous\n"
    346 );
    347 
    348 #elif defined(VGP_ppc64_linux)
    349 /* Due to the need to return 65 bits of result, this is completely
    350    different from the ppc32 case.  The single arg register points to a
    351    7-word block containing the syscall # and the 6 args.  The syscall
    352    result proper is put in [0] of the block, and %cr0.so is in the
    353    bottom bit of [1]. */
    354 extern void do_syscall_WRK ( ULong* argblock );
    355 asm(
    356 ".align   2\n"
    357 ".globl   do_syscall_WRK\n"
    358 ".section \".opd\",\"aw\"\n"
    359 ".align   3\n"
    360 "do_syscall_WRK:\n"
    361 ".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
    362 ".previous\n"
    363 ".type    .do_syscall_WRK,@function\n"
    364 ".globl   .do_syscall_WRK\n"
    365 ".do_syscall_WRK:\n"
    366 "        std  3,-16(1)\n"  /* stash arg */
    367 "        ld   8, 48(3)\n"  /* sc arg 6 */
    368 "        ld   7, 40(3)\n"  /* sc arg 5 */
    369 "        ld   6, 32(3)\n"  /* sc arg 4 */
    370 "        ld   5, 24(3)\n"  /* sc arg 3 */
    371 "        ld   4, 16(3)\n"  /* sc arg 2 */
    372 "        ld   0,  0(3)\n"  /* sc number */
    373 "        ld   3,  8(3)\n"  /* sc arg 1 */
    374 "        sc\n"             /* result in r3 and cr0.so */
    375 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
    376 "        std  3,0(5)\n"    /* argblock[0] = r3 */
    377 "        mfcr 3\n"
    378 "        srwi 3,3,28\n"
    379 "        andi. 3,3,1\n"
    380 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
    381 "        blr\n"
    382 );
    383 
    384 #elif defined(VGP_arm_linux)
    385 /* I think the conventions are:
    386    args  in r0 r1 r2 r3 r4 r5
    387    sysno in r7
    388    return value in r0, w/ same conventions as x86-linux, viz r0 in
    389    -4096 .. -1 is an error value.  All other values are success
    390    values.
    391 */
    392 extern UWord do_syscall_WRK (
    393           UWord a1, UWord a2, UWord a3,
    394           UWord a4, UWord a5, UWord a6,
    395           UWord syscall_no
    396        );
    397 asm(
    398 ".text\n"
    399 "do_syscall_WRK:\n"
    400 "         push    {r4, r5, r7}\n"
    401 "         ldr     r4, [sp, #12]\n"
    402 "         ldr     r5, [sp, #16]\n"
    403 "         ldr     r7, [sp, #20]\n"
    404 "         svc     0x0\n"
    405 "         pop     {r4, r5, r7}\n"
    406 "         bx      lr\n"
    407 ".previous\n"
    408 );
    409 
    410 #elif defined(VGP_x86_darwin)
    411 
    412 /* Incoming args (syscall number + up to 8 args) come in on the stack
    413 
    414    The kernel's syscall calling convention is:
    415    * the syscall number goes in eax
    416    * the args are passed to the syscall on the stack,
    417      pushed onto the stack R->L (that is, the usual x86
    418      calling conventions, with the leftmost arg at the lowest
    419      address)
    420    Call instruction:
    421    * UNIX: sysenter
    422    * UNIX: int $0x80
    423    * MACH: int $0x81
    424    * MDEP: int $0x82
    425    Note that the call type can be determined from the syscall number;
    426    there is no need to inspect the actual instruction.  Although obviously
    427    the instruction must match.
    428    Return value:
    429    * MACH,MDEP: the return value comes back in eax
    430    * UNIX: the return value comes back in edx:eax (hi32:lo32)
    431    Error:
    432    * MACH,MDEP: no error is returned
    433    * UNIX: the carry flag indicates success or failure
    434 
    435    nb here, sizeof(UWord) == sizeof(UInt)
    436 */
    437 
    438 __private_extern__ ULong
    439 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    440                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    441                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    442                       UWord syscall_no, /* 36(esp) */
    443                       /*OUT*/UInt* errflag /* 40(esp) */ );
    444 // Unix syscall: 64-bit return in edx:eax, with LSB in eax
    445 // error indicated by carry flag: clear=good, set=bad
    446 asm(".private_extern _do_syscall_unix_WRK\n"
    447     "_do_syscall_unix_WRK:\n"
    448     "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
    449     "        movl    $0, (%ecx)       \n"
    450     "        movl    36(%esp), %eax   \n"
    451     "        int     $0x80            \n"
    452     "        jnc     1f               \n"  /* jump if success */
    453     "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
    454     "        movl    $1, (%ecx)       \n"
    455     "    1:  ret                      \n"
    456     );
    457 
    458 __private_extern__ UInt
    459 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    460                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    461                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    462                       UWord syscall_no /* 36(esp) */ );
    463 // Mach trap: 32-bit result in %eax, no error flag
    464 asm(".private_extern _do_syscall_mach_WRK\n"
    465     "_do_syscall_mach_WRK:\n"
    466     "        movl    36(%esp), %eax   \n"
    467     "        int     $0x81            \n"
    468     "        ret                      \n"
    469     );
    470 
    471 __private_extern__ UInt
    472 do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    473                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    474                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    475                       UWord syscall_no /* 36(esp) */ );
    476 // mdep trap: 32-bit result in %eax, no error flag
    477 asm(
    478     ".private_extern _do_syscall_mdep_WRK\n"
    479     "_do_syscall_mdep_WRK:\n"
    480     "        movl    36(%esp), %eax   \n"
    481     "        int     $0x82            \n"
    482     "        ret                      \n"
    483     );
    484 
    485 
    486 #elif defined(VGP_amd64_darwin)
    487 
    488 /* Incoming args (syscall number + up to 8 args) come in registers and stack
    489 
    490    The kernel's syscall calling convention is:
    491    * the syscall number goes in rax
    492    * the args are passed to the syscall in registers and the stack
    493    * the call instruction is 'syscall'
    494    Return value:
    495    * MACH,MDEP: the return value comes back in rax
    496    * UNIX: the return value comes back in rdx:rax (hi64:lo64)
    497    Error:
    498    * MACH,MDEP: no error is returned
    499    * UNIX: the carry flag indicates success or failure
    500 
    501    nb here, sizeof(UWord) == sizeof(ULong)
    502 */
    503 
    504 __private_extern__ UWord
    505 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    506                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    507                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    508                       UWord syscall_no,             /* 24(rsp) */
    509                       /*OUT*/ULong* errflag,        /* 32(rsp) */
    510                       /*OUT*/ULong* res2 );         /* 40(rsp) */
    511 // Unix syscall: 128-bit return in rax:rdx, with LSB in rax
    512 // error indicated by carry flag: clear=good, set=bad
    513 asm(".private_extern _do_syscall_unix_WRK\n"
    514     "_do_syscall_unix_WRK:\n"
    515     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    516     "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
    517     "        movq    $0, (%rax)       \n"
    518     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    519     "        syscall                  \n"
    520     "        jnc     1f               \n"  /* jump if success */
    521     "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
    522     "        movq    $1, (%rcx)       \n"
    523     "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
    524     "        movq    %rdx, (%rcx)     \n"
    525     "        retq                     \n"  /* return 1st result word */
    526     );
    527 
    528 __private_extern__ UWord
    529 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    530                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    531                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    532                       UWord syscall_no );           /* 24(rsp) */
    533 // Mach trap: 64-bit result, no error flag
    534 asm(".private_extern _do_syscall_mach_WRK\n"
    535     "_do_syscall_mach_WRK:\n"
    536     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    537     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    538     "        syscall                  \n"
    539     "        retq                     \n"
    540     );
    541 
    542 #elif defined(VGP_s390x_linux)
    543 
    544 static UWord do_syscall_WRK (
    545    UWord syscall_no,
    546    UWord arg1, UWord arg2, UWord arg3,
    547    UWord arg4, UWord arg5, UWord arg6
    548    )
    549 {
    550    register UWord __arg1 asm("2") = arg1;
    551    register UWord __arg2 asm("3") = arg2;
    552    register UWord __arg3 asm("4") = arg3;
    553    register UWord __arg4 asm("5") = arg4;
    554    register UWord __arg5 asm("6") = arg5;
    555    register UWord __arg6 asm("7") = arg6;
    556    register ULong __svcres asm("2");
    557 
    558    __asm__ __volatile__ (
    559                  "lgr %%r1,%1\n\t"
    560                  "svc 0\n\t"
    561 		: "=d" (__svcres)
    562 		: "a" (syscall_no),
    563 		  "0" (__arg1),
    564 		  "d" (__arg2),
    565 		  "d" (__arg3),
    566 		  "d" (__arg4),
    567 		  "d" (__arg5),
    568 		  "d" (__arg6)
    569 		: "1", "cc", "memory");
    570 
    571    return (UWord) (__svcres);
    572 }
    573 
    574 #else
    575 #  error Unknown platform
    576 #endif
    577 
    578 
    579 /* Finally, the generic code.  This sends the call to the right
    580    helper. */
    581 
    582 SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
    583                                       UWord a4, UWord a5, UWord a6,
    584                                       UWord a7, UWord a8 )
    585 {
    586 #  if defined(VGP_x86_linux)
    587    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    588    return VG_(mk_SysRes_x86_linux)( val );
    589 
    590 #  elif defined(VGP_amd64_linux)
    591    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    592    return VG_(mk_SysRes_amd64_linux)( val );
    593 
    594 #  elif defined(VGP_ppc32_linux)
    595    ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    596    UInt  val     = (UInt)(ret>>32);
    597    UInt  cr0so   = (UInt)(ret);
    598    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
    599 
    600 #  elif defined(VGP_ppc64_linux)
    601    ULong argblock[7];
    602    argblock[0] = sysno;
    603    argblock[1] = a1;
    604    argblock[2] = a2;
    605    argblock[3] = a3;
    606    argblock[4] = a4;
    607    argblock[5] = a5;
    608    argblock[6] = a6;
    609    do_syscall_WRK( &argblock[0] );
    610    return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
    611 
    612 #  elif defined(VGP_arm_linux)
    613    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
    614    return VG_(mk_SysRes_arm_linux)( val );
    615 
    616 #  elif defined(VGP_x86_darwin)
    617    UInt  wLO = 0, wHI = 0, err = 0;
    618    ULong u64;
    619    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    620    switch (scclass) {
    621       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    622          u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    623                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
    624          wLO = (UInt)u64;
    625          wHI = (UInt)(u64 >> 32);
    626          break;
    627       case VG_DARWIN_SYSCALL_CLASS_MACH:
    628          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    629                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    630          err = 0;
    631          break;
    632       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    633          wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    634                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    635          err = 0;
    636          break;
    637       default:
    638          vg_assert(0);
    639          break;
    640    }
    641    return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
    642 
    643 #  elif defined(VGP_amd64_darwin)
    644    ULong wLO = 0, wHI = 0, err = 0;
    645    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    646    switch (scclass) {
    647       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    648          wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    649                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
    650          break;
    651       case VG_DARWIN_SYSCALL_CLASS_MACH:
    652       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    653          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    654                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    655          err = 0;
    656          break;
    657       default:
    658          vg_assert(0);
    659          break;
    660    }
    661    return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
    662 
    663 #elif defined(VGP_s390x_linux)
    664    UWord val;
    665 
    666    if (sysno == __NR_mmap) {
    667      ULong argbuf[6];
    668 
    669      argbuf[0] = a1;
    670      argbuf[1] = a2;
    671      argbuf[2] = a3;
    672      argbuf[3] = a4;
    673      argbuf[4] = a5;
    674      argbuf[5] = a6;
    675      val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
    676    } else {
    677      val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    678    }
    679 
    680    return VG_(mk_SysRes_s390x_linux)( val );
    681 #else
    682 #  error Unknown platform
    683 #endif
    684 }
    685 
    686 /* ---------------------------------------------------------------------
    687    Names of errors.
    688    ------------------------------------------------------------------ */
    689 
    690 /* Return a string which gives the name of an error value.  Note,
    691    unlike the standard C syserror fn, the returned string is not
    692    malloc-allocated or writable -- treat it as a constant.
    693    TODO: implement this properly. */
    694 
    695 const HChar* VG_(strerror) ( UWord errnum )
    696 {
    697    switch (errnum) {
    698       case VKI_EPERM:       return "Operation not permitted";
    699       case VKI_ENOENT:      return "No such file or directory";
    700       case VKI_ESRCH:       return "No such process";
    701       case VKI_EINTR:       return "Interrupted system call";
    702       case VKI_EBADF:       return "Bad file number";
    703       case VKI_EAGAIN:      return "Try again";
    704       case VKI_ENOMEM:      return "Out of memory";
    705       case VKI_EACCES:      return "Permission denied";
    706       case VKI_EFAULT:      return "Bad address";
    707       case VKI_EEXIST:      return "File exists";
    708       case VKI_EINVAL:      return "Invalid argument";
    709       case VKI_EMFILE:      return "Too many open files";
    710       case VKI_ENOSYS:      return "Function not implemented";
    711       case VKI_EOVERFLOW:   return "Value too large for defined data type";
    712 #     if defined(VKI_ERESTARTSYS)
    713       case VKI_ERESTARTSYS: return "ERESTARTSYS";
    714 #     endif
    715       default:              return "VG_(strerror): unknown error";
    716    }
    717 }
    718 
    719 
    720 /*--------------------------------------------------------------------*/
    721 /*--- end                                                        ---*/
    722 /*--------------------------------------------------------------------*/
    723