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-2013 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._valEx   = 0; /* unused except on mips-linux */
     66    res._isError = val >= -4095 && val <= -1;
     67    if (res._isError) {
     68       res._val = (UInt)(-val);
     69    } else {
     70       res._val = (UInt)val;
     71    }
     72    return res;
     73 }
     74 
     75 /* Similarly .. */
     76 SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
     77    SysRes res;
     78    res._valEx   = 0; /* unused except on mips-linux */
     79    res._isError = val >= -4095 && val <= -1;
     80    if (res._isError) {
     81       res._val = (ULong)(-val);
     82    } else {
     83       res._val = (ULong)val;
     84    }
     85    return res;
     86 }
     87 
     88 /* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speak) */
     89 /* Note this must be in the bottom bit of the second arg */
     90 SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
     91    SysRes res;
     92    res._valEx   = 0; /* unused except on mips-linux */
     93    res._isError = (cr0so & 1) != 0;
     94    res._val     = val;
     95    return res;
     96 }
     97 
     98 /* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
     99 SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
    100    SysRes res;
    101    res._valEx   = 0; /* unused except on mips-linux */
    102    res._isError = (cr0so & 1) != 0;
    103    res._val     = val;
    104    return res;
    105 }
    106 
    107 SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
    108    SysRes res;
    109    res._valEx   = 0; /* unused except on mips-linux */
    110    res._isError = val >= -4095 && val <= -1;
    111    if (res._isError) {
    112       res._val = -val;
    113    } else {
    114       res._val = val;
    115    }
    116    return res;
    117 }
    118 
    119 SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
    120    SysRes res;
    121    res._valEx   = 0; /* unused except on mips-linux */
    122    res._isError = val >= -4095 && val <= -1;
    123    if (res._isError) {
    124       res._val = (UInt)(-val);
    125    } else {
    126       res._val = (UInt)val;
    127    }
    128    return res;
    129 }
    130 
    131 SysRes VG_(mk_SysRes_arm64_linux) ( Long val ) {
    132    SysRes res;
    133    res._valEx   = 0; /* unused except on mips-linux */
    134    res._isError = val >= -4095 && val <= -1;
    135    if (res._isError) {
    136       res._val = (ULong)(-val);
    137    } else {
    138       res._val = (ULong)val;
    139    }
    140    return res;
    141 }
    142 
    143 /* MIPS uses a3 != 0 to flag an error */
    144 SysRes VG_(mk_SysRes_mips32_linux) ( UWord v0, UWord v1, UWord a3 ) {
    145    SysRes res;
    146    res._isError = (a3 != (UWord)0);
    147    res._val     = v0;
    148    res._valEx   = v1;
    149    return res;
    150 }
    151 
    152 /* MIPS uses a3 != 0 to flag an error */
    153 SysRes VG_(mk_SysRes_mips64_linux) ( ULong v0, ULong v1, ULong a3 ) {
    154    SysRes res;
    155    res._isError = (a3 != (ULong)0);
    156    res._val     = v0;
    157    res._valEx   = v1;
    158    return res;
    159 }
    160 
    161 /* Generic constructors. */
    162 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    163    SysRes r;
    164    r._valEx   = 0; /* unused except on mips-linux */
    165    r._isError = True;
    166    r._val     = err;
    167    return r;
    168 }
    169 
    170 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    171    SysRes r;
    172    r._valEx   = 0; /* unused except on mips-linux */
    173    r._isError = False;
    174    r._val     = res;
    175    return r;
    176 }
    177 
    178 
    179 #elif defined(VGO_darwin)
    180 
    181 /* Darwin: Some syscalls return a double-word result. */
    182 SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
    183                                    UInt wHI, UInt wLO )
    184 {
    185    SysRes res;
    186    res._wHI  = 0;
    187    res._wLO  = 0;
    188    res._mode = 0; /* invalid */
    189    vg_assert(isErr == False || isErr == True);
    190    vg_assert(sizeof(UWord) == sizeof(UInt));
    191    switch (scclass) {
    192       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    193          res._wLO  = wLO;
    194          res._wHI  = wHI;
    195          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    196          break;
    197       case VG_DARWIN_SYSCALL_CLASS_MACH:
    198          vg_assert(!isErr);
    199          vg_assert(wHI == 0);
    200          res._wLO  = wLO;
    201          res._mode = SysRes_MACH;
    202          break;
    203       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    204          vg_assert(!isErr);
    205          vg_assert(wHI == 0);
    206          res._wLO  = wLO;
    207          res._mode = SysRes_MDEP;
    208          break;
    209       default:
    210          vg_assert(0);
    211    }
    212    return res;
    213 }
    214 
    215 SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
    216                                      ULong wHI, ULong wLO )
    217 {
    218    SysRes res;
    219    res._wHI  = 0;
    220    res._wLO  = 0;
    221    res._mode = 0; /* invalid */
    222    vg_assert(isErr == False || isErr == True);
    223    vg_assert(sizeof(UWord) == sizeof(ULong));
    224    switch (scclass) {
    225       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    226          res._wLO  = wLO;
    227          res._wHI  = wHI;
    228          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    229          break;
    230       case VG_DARWIN_SYSCALL_CLASS_MACH:
    231          vg_assert(!isErr);
    232          vg_assert(wHI == 0);
    233          res._wLO  = wLO;
    234          res._mode = SysRes_MACH;
    235          break;
    236       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    237          vg_assert(!isErr);
    238          vg_assert(wHI == 0);
    239          res._wLO  = wLO;
    240          res._mode = SysRes_MDEP;
    241          break;
    242       default:
    243          vg_assert(0);
    244    }
    245    return res;
    246 }
    247 
    248 /* Generic constructors.  We assume (without checking if this makes
    249    any sense, from the caller's point of view) that these are for the
    250    UNIX style of syscall. */
    251 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    252    SysRes r;
    253    r._wHI  = 0;
    254    r._wLO  = err;
    255    r._mode = SysRes_UNIX_ERR;
    256    return r;
    257 }
    258 
    259 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    260    SysRes r;
    261    r._wHI  = 0;
    262    r._wLO  = res;
    263    r._mode = SysRes_UNIX_OK;
    264    return r;
    265 }
    266 
    267 
    268 #else
    269 #  error "Unknown OS"
    270 #endif
    271 
    272 
    273 /* ---------------------------------------------------------------------
    274    VG_(do_syscall): A function for doing syscalls.
    275    ------------------------------------------------------------------ */
    276 
    277 #if defined(VGP_x86_linux)
    278 /* Incoming args (syscall number + up to 6 args) come on the stack.
    279    (ie. the C calling convention).
    280 
    281    The syscall number goes in %eax.  The args are passed to the syscall in
    282    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
    283    calling convention.
    284 
    285    %eax gets the return value.  Not sure which registers the kernel
    286    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
    287    %ebp).
    288 */
    289 extern UWord do_syscall_WRK (
    290           UWord syscall_no,
    291           UWord a1, UWord a2, UWord a3,
    292           UWord a4, UWord a5, UWord a6
    293        );
    294 asm(
    295 ".text\n"
    296 ".globl do_syscall_WRK\n"
    297 "do_syscall_WRK:\n"
    298 "	push	%esi\n"
    299 "	push	%edi\n"
    300 "	push	%ebx\n"
    301 "	push	%ebp\n"
    302 "	movl	16+ 4(%esp),%eax\n"
    303 "	movl	16+ 8(%esp),%ebx\n"
    304 "	movl	16+12(%esp),%ecx\n"
    305 "	movl	16+16(%esp),%edx\n"
    306 "	movl	16+20(%esp),%esi\n"
    307 "	movl	16+24(%esp),%edi\n"
    308 "	movl	16+28(%esp),%ebp\n"
    309 "	int	$0x80\n"
    310 "	popl	%ebp\n"
    311 "	popl	%ebx\n"
    312 "	popl	%edi\n"
    313 "	popl	%esi\n"
    314 "	ret\n"
    315 ".previous\n"
    316 );
    317 
    318 #elif defined(VGP_amd64_linux)
    319 /* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
    320    %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
    321    calling convention).
    322 
    323    The syscall number goes in %rax.  The args are passed to the syscall in
    324    the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
    325    ie. the kernel's syscall calling convention.
    326 
    327    %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
    328    no matter, they are caller-save (the syscall clobbers no callee-save
    329    regs, so we don't have to do any register saving/restoring).
    330 */
    331 extern UWord do_syscall_WRK (
    332           UWord syscall_no,
    333           UWord a1, UWord a2, UWord a3,
    334           UWord a4, UWord a5, UWord a6
    335        );
    336 asm(
    337 ".text\n"
    338 ".globl do_syscall_WRK\n"
    339 "do_syscall_WRK:\n"
    340         /* Convert function calling convention --> syscall calling
    341            convention */
    342 "	movq	%rdi, %rax\n"
    343 "	movq	%rsi, %rdi\n"
    344 "	movq	%rdx, %rsi\n"
    345 "	movq	%rcx, %rdx\n"
    346 "	movq	%r8,  %r10\n"
    347 "	movq	%r9,  %r8\n"
    348 "	movq    8(%rsp), %r9\n"	 /* last arg from stack */
    349 "	syscall\n"
    350 "	ret\n"
    351 ".previous\n"
    352 );
    353 
    354 #elif defined(VGP_ppc32_linux)
    355 /* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
    356 
    357    The syscall number goes in %r0.  The args are passed to the syscall in
    358    the regs %r3:%r8, i.e. the kernel's syscall calling convention.
    359 
    360    The %cr0.so bit flags an error.
    361    We return the syscall return value in %r3, and the %cr0.so in
    362    the lowest bit of %r4.
    363    We return a ULong, of which %r3 is the high word, and %r4 the low.
    364    No callee-save regs are clobbered, so no saving/restoring is needed.
    365 */
    366 extern ULong do_syscall_WRK (
    367           UWord syscall_no,
    368           UWord a1, UWord a2, UWord a3,
    369           UWord a4, UWord a5, UWord a6
    370        );
    371 asm(
    372 ".text\n"
    373 ".globl do_syscall_WRK\n"
    374 "do_syscall_WRK:\n"
    375 "        mr      0,3\n"
    376 "        mr      3,4\n"
    377 "        mr      4,5\n"
    378 "        mr      5,6\n"
    379 "        mr      6,7\n"
    380 "        mr      7,8\n"
    381 "        mr      8,9\n"
    382 "        sc\n"                  /* syscall: sets %cr0.so on error         */
    383 "        mfcr    4\n"           /* %cr -> low word of return var          */
    384 "        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
    385 "        blr\n"                 /* and return                             */
    386 ".previous\n"
    387 );
    388 
    389 #elif defined(VGP_ppc64_linux)
    390 /* Due to the need to return 65 bits of result, this is completely
    391    different from the ppc32 case.  The single arg register points to a
    392    7-word block containing the syscall # and the 6 args.  The syscall
    393    result proper is put in [0] of the block, and %cr0.so is in the
    394    bottom bit of [1]. */
    395 extern void do_syscall_WRK ( ULong* argblock );
    396 asm(
    397 ".align   2\n"
    398 ".globl   do_syscall_WRK\n"
    399 ".section \".opd\",\"aw\"\n"
    400 ".align   3\n"
    401 "do_syscall_WRK:\n"
    402 ".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
    403 ".previous\n"
    404 ".type    .do_syscall_WRK,@function\n"
    405 ".globl   .do_syscall_WRK\n"
    406 ".do_syscall_WRK:\n"
    407 "        std  3,-16(1)\n"  /* stash arg */
    408 "        ld   8, 48(3)\n"  /* sc arg 6 */
    409 "        ld   7, 40(3)\n"  /* sc arg 5 */
    410 "        ld   6, 32(3)\n"  /* sc arg 4 */
    411 "        ld   5, 24(3)\n"  /* sc arg 3 */
    412 "        ld   4, 16(3)\n"  /* sc arg 2 */
    413 "        ld   0,  0(3)\n"  /* sc number */
    414 "        ld   3,  8(3)\n"  /* sc arg 1 */
    415 "        sc\n"             /* result in r3 and cr0.so */
    416 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
    417 "        std  3,0(5)\n"    /* argblock[0] = r3 */
    418 "        mfcr 3\n"
    419 "        srwi 3,3,28\n"
    420 "        andi. 3,3,1\n"
    421 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
    422 "        blr\n"
    423 );
    424 
    425 #elif defined(VGP_arm_linux)
    426 /* I think the conventions are:
    427    args  in r0 r1 r2 r3 r4 r5
    428    sysno in r7
    429    return value in r0, w/ same conventions as x86-linux, viz r0 in
    430    -4096 .. -1 is an error value.  All other values are success
    431    values.
    432 */
    433 extern UWord do_syscall_WRK (
    434           UWord a1, UWord a2, UWord a3,
    435           UWord a4, UWord a5, UWord a6,
    436           UWord syscall_no
    437        );
    438 asm(
    439 ".text\n"
    440 ".globl do_syscall_WRK\n"
    441 "do_syscall_WRK:\n"
    442 "         push    {r4, r5, r7}\n"
    443 "         ldr     r4, [sp, #12]\n"
    444 "         ldr     r5, [sp, #16]\n"
    445 "         ldr     r7, [sp, #20]\n"
    446 "         svc     0x0\n"
    447 "         pop     {r4, r5, r7}\n"
    448 "         bx      lr\n"
    449 ".previous\n"
    450 );
    451 
    452 #elif defined(VGP_arm64_linux)
    453 /* I think the conventions are:
    454    args  in r0 r1 r2 r3 r4 r5
    455    sysno in r8
    456    return value in r0, w/ same conventions as x86-linux, viz r0 in
    457    -4096 .. -1 is an error value.  All other values are success
    458    values.
    459 
    460    r0 to r5 remain unchanged, but syscall_no is in r6 and needs
    461    to be moved to r8 (??)
    462 */
    463 extern UWord do_syscall_WRK (
    464           UWord a1, UWord a2, UWord a3,
    465           UWord a4, UWord a5, UWord a6,
    466           UWord syscall_no
    467        );
    468 asm(
    469 ".text\n"
    470 ".globl do_syscall_WRK\n"
    471 "do_syscall_WRK:\n"
    472 "        mov x8, x6\n"
    473 "        mov x6, 0\n"
    474 "        mov x7, 0\n"
    475 "        svc 0\n"
    476 "        ret\n"
    477 ".previous\n"
    478 );
    479 
    480 #elif defined(VGP_x86_darwin)
    481 
    482 /* Incoming args (syscall number + up to 8 args) come in on the stack
    483 
    484    The kernel's syscall calling convention is:
    485    * the syscall number goes in eax
    486    * the args are passed to the syscall on the stack,
    487      pushed onto the stack R->L (that is, the usual x86
    488      calling conventions, with the leftmost arg at the lowest
    489      address)
    490    Call instruction:
    491    * UNIX: sysenter
    492    * UNIX: int $0x80
    493    * MACH: int $0x81
    494    * MDEP: int $0x82
    495    Note that the call type can be determined from the syscall number;
    496    there is no need to inspect the actual instruction.  Although obviously
    497    the instruction must match.
    498    Return value:
    499    * MACH,MDEP: the return value comes back in eax
    500    * UNIX: the return value comes back in edx:eax (hi32:lo32)
    501    Error:
    502    * MACH,MDEP: no error is returned
    503    * UNIX: the carry flag indicates success or failure
    504 
    505    nb here, sizeof(UWord) == sizeof(UInt)
    506 */
    507 
    508 __private_extern__ ULong
    509 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    510                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    511                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    512                       UWord syscall_no, /* 36(esp) */
    513                       /*OUT*/UInt* errflag /* 40(esp) */ );
    514 // Unix syscall: 64-bit return in edx:eax, with LSB in eax
    515 // error indicated by carry flag: clear=good, set=bad
    516 asm(".private_extern _do_syscall_unix_WRK\n"
    517     "_do_syscall_unix_WRK:\n"
    518     "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
    519     "        movl    $0, (%ecx)       \n"
    520     "        movl    36(%esp), %eax   \n"
    521     "        int     $0x80            \n"
    522     "        jnc     1f               \n"  /* jump if success */
    523     "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
    524     "        movl    $1, (%ecx)       \n"
    525     "    1:  ret                      \n"
    526     );
    527 
    528 __private_extern__ UInt
    529 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    530                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    531                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    532                       UWord syscall_no /* 36(esp) */ );
    533 // Mach trap: 32-bit result in %eax, no error flag
    534 asm(".private_extern _do_syscall_mach_WRK\n"
    535     "_do_syscall_mach_WRK:\n"
    536     "        movl    36(%esp), %eax   \n"
    537     "        int     $0x81            \n"
    538     "        ret                      \n"
    539     );
    540 
    541 __private_extern__ UInt
    542 do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    543                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    544                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    545                       UWord syscall_no /* 36(esp) */ );
    546 // mdep trap: 32-bit result in %eax, no error flag
    547 asm(
    548     ".private_extern _do_syscall_mdep_WRK\n"
    549     "_do_syscall_mdep_WRK:\n"
    550     "        movl    36(%esp), %eax   \n"
    551     "        int     $0x82            \n"
    552     "        ret                      \n"
    553     );
    554 
    555 
    556 #elif defined(VGP_amd64_darwin)
    557 
    558 /* Incoming args (syscall number + up to 8 args) come in registers and stack
    559 
    560    The kernel's syscall calling convention is:
    561    * the syscall number goes in rax
    562    * the args are passed to the syscall in registers and the stack
    563    * the call instruction is 'syscall'
    564    Return value:
    565    * MACH,MDEP: the return value comes back in rax
    566    * UNIX: the return value comes back in rdx:rax (hi64:lo64)
    567    Error:
    568    * MACH,MDEP: no error is returned
    569    * UNIX: the carry flag indicates success or failure
    570 
    571    nb here, sizeof(UWord) == sizeof(ULong)
    572 */
    573 
    574 __private_extern__ UWord
    575 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    576                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    577                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    578                       UWord syscall_no,             /* 24(rsp) */
    579                       /*OUT*/ULong* errflag,        /* 32(rsp) */
    580                       /*OUT*/ULong* res2 );         /* 40(rsp) */
    581 // Unix syscall: 128-bit return in rax:rdx, with LSB in rax
    582 // error indicated by carry flag: clear=good, set=bad
    583 asm(".private_extern _do_syscall_unix_WRK\n"
    584     "_do_syscall_unix_WRK:\n"
    585     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    586     "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
    587     "        movq    $0, (%rax)       \n"
    588     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    589     "        syscall                  \n"
    590     "        jnc     1f               \n"  /* jump if success */
    591     "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
    592     "        movq    $1, (%rcx)       \n"
    593     "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
    594     "        movq    %rdx, (%rcx)     \n"
    595     "        retq                     \n"  /* return 1st result word */
    596     );
    597 
    598 __private_extern__ UWord
    599 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    600                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    601                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    602                       UWord syscall_no );           /* 24(rsp) */
    603 // Mach trap: 64-bit result, no error flag
    604 asm(".private_extern _do_syscall_mach_WRK\n"
    605     "_do_syscall_mach_WRK:\n"
    606     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    607     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    608     "        syscall                  \n"
    609     "        retq                     \n"
    610     );
    611 
    612 #elif defined(VGP_s390x_linux)
    613 
    614 static UWord do_syscall_WRK (
    615    UWord syscall_no,
    616    UWord arg1, UWord arg2, UWord arg3,
    617    UWord arg4, UWord arg5, UWord arg6
    618    )
    619 {
    620    register UWord __arg1 asm("2") = arg1;
    621    register UWord __arg2 asm("3") = arg2;
    622    register UWord __arg3 asm("4") = arg3;
    623    register UWord __arg4 asm("5") = arg4;
    624    register UWord __arg5 asm("6") = arg5;
    625    register UWord __arg6 asm("7") = arg6;
    626    register ULong __svcres asm("2");
    627 
    628    __asm__ __volatile__ (
    629                  "lgr %%r1,%1\n\t"
    630                  "svc 0\n\t"
    631 		: "=d" (__svcres)
    632 		: "a" (syscall_no),
    633 		  "0" (__arg1),
    634 		  "d" (__arg2),
    635 		  "d" (__arg3),
    636 		  "d" (__arg4),
    637 		  "d" (__arg5),
    638 		  "d" (__arg6)
    639 		: "1", "cc", "memory");
    640 
    641    return (UWord) (__svcres);
    642 }
    643 
    644 #elif defined(VGP_mips32_linux)
    645 /* Incoming args (syscall number + up to 6 args) come in a0 - a3 and stack.
    646 
    647    The syscall number goes in v0.  The args are passed to the syscall in
    648    the regs a0 - a3 and stack, i.e. the kernel's syscall calling convention.
    649 
    650    (a3 != 0) flags an error.
    651    We return the syscall return value in v0.
    652    MIPS version
    653 */
    654 extern int do_syscall_WRK (
    655           int a1, int a2, int a3,
    656           int a4, int a5, int a6, int syscall_no, UWord *err,
    657           UWord *valHi, UWord* valLo
    658        );
    659 asm(
    660 ".globl do_syscall_WRK\n"
    661 ".ent do_syscall_WRK\n"
    662 ".text\n"
    663 "do_syscall_WRK:\n"
    664 "   lw $2, 24($29)\n"
    665 "   syscall\n"
    666 "   lw $8, 28($29)\n"
    667 "   sw $7, ($8)\n"
    668 "   lw $8, 32($29)\n"
    669 "   sw $3, ($8)\n"   // store valHi
    670 "   lw $8, 36($29)\n"
    671 "   sw $2, ($8)\n"   // store valLo
    672 "   jr $31\n"
    673 "   nop\n"
    674 ".previous\n"
    675 ".end do_syscall_WRK\n"
    676 );
    677 
    678 #elif defined(VGP_mips64_linux)
    679 extern UWord do_syscall_WRK ( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5,
    680                               UWord a6, UWord syscall_no, ULong* V1_val );
    681 asm (
    682 ".text\n"
    683 ".globl do_syscall_WRK\n"
    684 "do_syscall_WRK:\n"
    685 "   daddiu $29, $29, -8\n"
    686 "   sd $11, 0($29)\n"
    687 "   move $2, $10\n"
    688 "   syscall\n"
    689 "   ld $11, 0($29)\n"
    690 "   daddiu $29, $29, 8\n"
    691 "   sd $3, 0($11)\n"  /* store vale of v1 in last param */
    692 "   sd $7, 8($11)\n"  /* store vale of a3 in last param */
    693 "   jr $31\n"
    694 ".previous\n"
    695 );
    696 
    697 #else
    698 #  error Unknown platform
    699 #endif
    700 
    701 
    702 /* Finally, the generic code.  This sends the call to the right
    703    helper. */
    704 
    705 SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
    706                                       UWord a4, UWord a5, UWord a6,
    707                                       UWord a7, UWord a8 )
    708 {
    709 #  if defined(VGP_x86_linux)
    710    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    711    return VG_(mk_SysRes_x86_linux)( val );
    712 
    713 #  elif defined(VGP_amd64_linux)
    714    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    715    return VG_(mk_SysRes_amd64_linux)( val );
    716 
    717 #  elif defined(VGP_ppc32_linux)
    718    ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    719    UInt  val     = (UInt)(ret>>32);
    720    UInt  cr0so   = (UInt)(ret);
    721    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
    722 
    723 #  elif defined(VGP_ppc64_linux)
    724    ULong argblock[7];
    725    argblock[0] = sysno;
    726    argblock[1] = a1;
    727    argblock[2] = a2;
    728    argblock[3] = a3;
    729    argblock[4] = a4;
    730    argblock[5] = a5;
    731    argblock[6] = a6;
    732    do_syscall_WRK( &argblock[0] );
    733    return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
    734 
    735 #  elif defined(VGP_arm_linux)
    736    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
    737    return VG_(mk_SysRes_arm_linux)( val );
    738 
    739 #  elif defined(VGP_arm64_linux)
    740    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
    741    return VG_(mk_SysRes_arm64_linux)( val );
    742 
    743 #  elif defined(VGP_x86_darwin)
    744    UInt  wLO = 0, wHI = 0, err = 0;
    745    ULong u64;
    746    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    747    switch (scclass) {
    748       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    749          u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    750                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
    751          wLO = (UInt)u64;
    752          wHI = (UInt)(u64 >> 32);
    753          break;
    754       case VG_DARWIN_SYSCALL_CLASS_MACH:
    755          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    756                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    757          err = 0;
    758          break;
    759       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    760          wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    761                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    762          err = 0;
    763          break;
    764       default:
    765          vg_assert(0);
    766          break;
    767    }
    768    return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
    769 
    770 #  elif defined(VGP_amd64_darwin)
    771    ULong wLO = 0, wHI = 0, err = 0;
    772    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    773    switch (scclass) {
    774       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    775          wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    776                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
    777          break;
    778       case VG_DARWIN_SYSCALL_CLASS_MACH:
    779       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    780          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    781                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    782          err = 0;
    783          break;
    784       default:
    785          vg_assert(0);
    786          break;
    787    }
    788    return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
    789 
    790 #elif defined(VGP_s390x_linux)
    791    UWord val;
    792 
    793    if (sysno == __NR_mmap) {
    794      ULong argbuf[6];
    795 
    796      argbuf[0] = a1;
    797      argbuf[1] = a2;
    798      argbuf[2] = a3;
    799      argbuf[3] = a4;
    800      argbuf[4] = a5;
    801      argbuf[5] = a6;
    802      val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
    803    } else {
    804      val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    805    }
    806 
    807    return VG_(mk_SysRes_s390x_linux)( val );
    808 
    809 #elif defined(VGP_mips32_linux)
    810    UWord err   = 0;
    811    UWord valHi = 0;
    812    UWord valLo = 0;
    813    (void) do_syscall_WRK(a1,a2,a3,a4,a5,a6, sysno,&err,&valHi,&valLo);
    814    return VG_(mk_SysRes_mips32_linux)( valLo, valHi, (ULong)err );
    815 
    816 #elif defined(VGP_mips64_linux)
    817    ULong v1_a3[2];
    818    v1_a3[0] = 0xFF00;
    819    v1_a3[1] = 0xFF00;
    820    ULong V0 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno,v1_a3);
    821    ULong V1 = (ULong)v1_a3[0];
    822    ULong A3 = (ULong)v1_a3[1];
    823    return VG_(mk_SysRes_mips64_linux)( V0, V1, A3 );
    824 
    825 #else
    826 #  error Unknown platform
    827 #endif
    828 }
    829 
    830 /* ---------------------------------------------------------------------
    831    Names of errors.
    832    ------------------------------------------------------------------ */
    833 
    834 /* Return a string which gives the name of an error value.  Note,
    835    unlike the standard C syserror fn, the returned string is not
    836    malloc-allocated or writable -- treat it as a constant.
    837    TODO: implement this properly. */
    838 
    839 const HChar* VG_(strerror) ( UWord errnum )
    840 {
    841    switch (errnum) {
    842    case VKI_EPERM:       return "Operation not permitted";
    843    case VKI_ENOENT:      return "No such file or directory";
    844    case VKI_ESRCH:       return "No such process";
    845    case VKI_EINTR:       return "Interrupted system call";
    846    case VKI_EIO:         return "Input/output error";
    847    case VKI_ENXIO:       return "No such device or address";
    848    case VKI_E2BIG:       return "Argument list too long";
    849    case VKI_ENOEXEC:     return "Exec format error";
    850    case VKI_EBADF:       return "Bad file descriptor";
    851    case VKI_ECHILD:      return "No child processes";
    852    case VKI_EAGAIN:      return "Resource temporarily unavailable";
    853    case VKI_ENOMEM:      return "Cannot allocate memory";
    854    case VKI_EACCES:      return "Permission denied";
    855    case VKI_EFAULT:      return "Bad address";
    856    case VKI_ENOTBLK:     return "Block device required";
    857    case VKI_EBUSY:       return "Device or resource busy";
    858    case VKI_EEXIST:      return "File exists";
    859    case VKI_EXDEV:       return "Invalid cross-device link";
    860    case VKI_ENODEV:      return "No such device";
    861    case VKI_ENOTDIR:     return "Not a directory";
    862    case VKI_EISDIR:      return "Is a directory";
    863    case VKI_EINVAL:      return "Invalid argument";
    864    case VKI_ENFILE:      return "Too many open files in system";
    865    case VKI_EMFILE:      return "Too many open files";
    866    case VKI_ENOTTY:      return "Inappropriate ioctl for device";
    867    case VKI_ETXTBSY:     return "Text file busy";
    868    case VKI_EFBIG:       return "File too large";
    869    case VKI_ENOSPC:      return "No space left on device";
    870    case VKI_ESPIPE:      return "Illegal seek";
    871    case VKI_EROFS:       return "Read-only file system";
    872    case VKI_EMLINK:      return "Too many links";
    873    case VKI_EPIPE:       return "Broken pipe";
    874    case VKI_EDOM:        return "Numerical argument out of domain";
    875    case VKI_ERANGE:      return "Numerical result out of range";
    876 
    877    case VKI_ENOSYS:      return "Function not implemented";
    878    case VKI_EOVERFLOW:   return "Value too large for defined data type";
    879 #     if defined(VKI_ERESTARTSYS)
    880       case VKI_ERESTARTSYS: return "ERESTARTSYS";
    881 #     endif
    882    default:              return "VG_(strerror): unknown error";
    883    }
    884 }
    885 
    886 
    887 /*--------------------------------------------------------------------*/
    888 /*--- end                                                          ---*/
    889 /*--------------------------------------------------------------------*/
    890