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-2017 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 /* Make a SysRes value from a syscall return value.  This is
     42    platform specific. */
     43 
     44 #if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
     45 
     46 SysRes VG_(mk_SysRes_mips32_linux) ( UWord v0, UWord v1, UWord a3 ) {
     47    /* MIPS uses a3 != 0 to flag an error */
     48    SysRes res;
     49    res._isError = (a3 != (UWord)0);
     50    res._val     = v0;
     51    res._valEx   = v1;
     52    return res;
     53 }
     54 
     55 SysRes VG_(mk_SysRes_mips64_linux) ( ULong v0, ULong v1, ULong a3 ) {
     56    /* MIPS uses a3 != 0 to flag an error */
     57    SysRes res;
     58    res._isError = (a3 != (ULong)0);
     59    res._val     = v0;
     60    res._valEx   = v1;
     61    return res;
     62 }
     63 
     64 /* Generic constructors. */
     65 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
     66    SysRes r;
     67    r._isError = True;
     68    r._val     = err;
     69    r._valEx   = 0;
     70    return r;
     71 }
     72 
     73 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
     74    SysRes r;
     75    r._isError = False;
     76    r._val     = res;
     77    r._valEx   = 0;
     78    return r;
     79 }
     80 
     81 SysRes VG_(mk_SysRes_SuccessEx) ( UWord res, UWord resEx ) {
     82    SysRes r;
     83    r._isError = False;
     84    r._val     = res;
     85    r._valEx   = resEx;
     86    return r;
     87 }
     88 
     89 
     90 #elif defined(VGO_linux) \
     91       && !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux)
     92 
     93 /*
     94    From:
     95    http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/
     96    linux/i386/sysdep.h?
     97    rev=1.28&content-type=text/x-cvsweb-markup&cvsroot=glibc
     98 
     99    Linux uses a negative return value to indicate syscall errors,
    100    unlike most Unices, which use the condition codes' carry flag.
    101 
    102    Since version 2.1 the return value of a system call might be
    103    negative even if the call succeeded.  E.g., the 'lseek' system call
    104    might return a large offset.  Therefore we must not anymore test
    105    for < 0, but test for a real error by making sure the value in %eax
    106    is a real error number.  Linus said he will make sure the no
    107    syscall returns a value in -1 .. -4095 as a valid result so we can
    108    safely test with -4095.
    109 */
    110 
    111 SysRes VG_(mk_SysRes_x86_linux) ( Int val ) {
    112    SysRes res;
    113    res._isError = val >= -4095 && val <= -1;
    114    if (res._isError) {
    115       res._val = (UInt)(-val);
    116    } else {
    117       res._val = (UInt)val;
    118    }
    119    return res;
    120 }
    121 
    122 /* Similarly .. */
    123 SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
    124    SysRes res;
    125    res._isError = val >= -4095 && val <= -1;
    126    if (res._isError) {
    127       res._val = (ULong)(-val);
    128    } else {
    129       res._val = (ULong)val;
    130    }
    131    return res;
    132 }
    133 
    134 /* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speak) */
    135 /* Note this must be in the bottom bit of the second arg */
    136 SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
    137    SysRes res;
    138    res._isError = (cr0so & 1) != 0;
    139    res._val     = val;
    140    return res;
    141 }
    142 
    143 /* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
    144 SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
    145    SysRes res;
    146    res._isError = (cr0so & 1) != 0;
    147    res._val     = val;
    148    return res;
    149 }
    150 
    151 SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
    152    SysRes res;
    153    res._isError = val >= -4095 && val <= -1;
    154    if (res._isError) {
    155       res._val = -val;
    156    } else {
    157       res._val = val;
    158    }
    159    return res;
    160 }
    161 
    162 SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
    163    SysRes res;
    164    res._isError = val >= -4095 && val <= -1;
    165    if (res._isError) {
    166       res._val = (UInt)(-val);
    167    } else {
    168       res._val = (UInt)val;
    169    }
    170    return res;
    171 }
    172 
    173 SysRes VG_(mk_SysRes_arm64_linux) ( Long val ) {
    174    SysRes res;
    175    res._isError = val >= -4095 && val <= -1;
    176    if (res._isError) {
    177       res._val = (ULong)(-val);
    178    } else {
    179       res._val = (ULong)val;
    180    }
    181    return res;
    182 }
    183 
    184 /* Generic constructors. */
    185 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    186    SysRes r;
    187    r._isError = True;
    188    r._val     = err;
    189    return r;
    190 }
    191 
    192 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    193    SysRes r;
    194    r._isError = False;
    195    r._val     = res;
    196    return r;
    197 }
    198 
    199 
    200 #elif defined(VGO_darwin)
    201 
    202 /* Darwin: Some syscalls return a double-word result. */
    203 SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
    204                                    UInt wHI, UInt wLO )
    205 {
    206    SysRes res;
    207    res._wHI  = 0;
    208    res._wLO  = 0;
    209    res._mode = 0; /* invalid */
    210    vg_assert(isErr == False || isErr == True);
    211    vg_assert(sizeof(UWord) == sizeof(UInt));
    212    switch (scclass) {
    213       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    214          res._wLO  = wLO;
    215          res._wHI  = wHI;
    216          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    217          break;
    218       case VG_DARWIN_SYSCALL_CLASS_MACH:
    219          vg_assert(!isErr);
    220          vg_assert(wHI == 0);
    221          res._wLO  = wLO;
    222          res._mode = SysRes_MACH;
    223          break;
    224       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    225          vg_assert(!isErr);
    226          vg_assert(wHI == 0);
    227          res._wLO  = wLO;
    228          res._mode = SysRes_MDEP;
    229          break;
    230       default:
    231          vg_assert(0);
    232    }
    233    return res;
    234 }
    235 
    236 SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
    237                                      ULong wHI, ULong wLO )
    238 {
    239    SysRes res;
    240    res._wHI  = 0;
    241    res._wLO  = 0;
    242    res._mode = 0; /* invalid */
    243    vg_assert(isErr == False || isErr == True);
    244    vg_assert(sizeof(UWord) == sizeof(ULong));
    245    switch (scclass) {
    246       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    247          res._wLO  = wLO;
    248          res._wHI  = wHI;
    249          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
    250          break;
    251       case VG_DARWIN_SYSCALL_CLASS_MACH:
    252          vg_assert(!isErr);
    253          vg_assert(wHI == 0);
    254          res._wLO  = wLO;
    255          res._mode = SysRes_MACH;
    256          break;
    257       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    258          vg_assert(!isErr);
    259          vg_assert(wHI == 0);
    260          res._wLO  = wLO;
    261          res._mode = SysRes_MDEP;
    262          break;
    263       default:
    264          vg_assert(0);
    265    }
    266    return res;
    267 }
    268 
    269 /* Generic constructors.  We assume (without checking if this makes
    270    any sense, from the caller's point of view) that these are for the
    271    UNIX style of syscall. */
    272 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    273    SysRes r;
    274    r._wHI  = 0;
    275    r._wLO  = err;
    276    r._mode = SysRes_UNIX_ERR;
    277    return r;
    278 }
    279 
    280 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    281    SysRes r;
    282    r._wHI  = 0;
    283    r._wLO  = res;
    284    r._mode = SysRes_UNIX_OK;
    285    return r;
    286 }
    287 
    288 
    289 #elif defined(VGO_solaris)
    290 
    291 /* Generic constructors. */
    292 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
    293    SysRes r;
    294    r._val     = err;
    295    r._val2    = 0;
    296    r._isError = True;
    297    return r;
    298 }
    299 
    300 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
    301    SysRes r;
    302    r._val     = res;
    303    r._val2    = 0;
    304    r._isError = False;
    305    return r;
    306 }
    307 
    308 SysRes VG_(mk_SysRes_x86_solaris) ( Bool isErr, UInt val, UInt val2 )
    309 {
    310    SysRes res;
    311 
    312    // stay sane
    313    vg_assert(isErr == True || isErr == False);
    314 
    315    res._val  = val;
    316    res._val2 = val2;
    317    res._isError = isErr;
    318    return res;
    319 }
    320 
    321 SysRes VG_(mk_SysRes_amd64_solaris) ( Bool isErr, ULong val, ULong val2 )
    322 {
    323    SysRes res;
    324 
    325    // stay sane
    326    vg_assert(isErr == True || isErr == False);
    327 
    328    res._val  = val;
    329    res._val2 = val2;
    330    res._isError = isErr;
    331    return res;
    332 }
    333 
    334 #else
    335 #  error "Unknown OS"
    336 #endif
    337 
    338 
    339 /* ---------------------------------------------------------------------
    340    VG_(do_syscall): A function for doing syscalls.
    341    ------------------------------------------------------------------ */
    342 
    343 #if defined(VGP_x86_linux)
    344 /* Incoming args (syscall number + up to 6 args) come on the stack.
    345    (ie. the C calling convention).
    346 
    347    The syscall number goes in %eax.  The args are passed to the syscall in
    348    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
    349    calling convention.
    350 
    351    %eax gets the return value.  Not sure which registers the kernel
    352    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
    353    %ebp).
    354 */
    355 extern UWord do_syscall_WRK (
    356           UWord syscall_no,
    357           UWord a1, UWord a2, UWord a3,
    358           UWord a4, UWord a5, UWord a6
    359        );
    360 asm(
    361 ".text\n"
    362 ".globl do_syscall_WRK\n"
    363 "do_syscall_WRK:\n"
    364 "	.cfi_startproc\n"
    365 "	push	%esi\n"
    366 "	.cfi_adjust_cfa_offset 4\n"
    367 "	.cfi_offset %esi, -8\n"
    368 "	push	%edi\n"
    369 "	.cfi_adjust_cfa_offset 4\n"
    370 "	.cfi_offset %edi, -12\n"
    371 "	push	%ebx\n"
    372 "	.cfi_adjust_cfa_offset 4\n"
    373 "	.cfi_offset %ebx, -16\n"
    374 "	push	%ebp\n"
    375 "	.cfi_adjust_cfa_offset 4\n"
    376 "	.cfi_offset %ebp, -20\n"
    377 "	movl	16+ 4(%esp),%eax\n"
    378 "	movl	16+ 8(%esp),%ebx\n"
    379 "	movl	16+12(%esp),%ecx\n"
    380 "	movl	16+16(%esp),%edx\n"
    381 "	movl	16+20(%esp),%esi\n"
    382 "	movl	16+24(%esp),%edi\n"
    383 "	movl	16+28(%esp),%ebp\n"
    384 "	int	$0x80\n"
    385 "	popl	%ebp\n"
    386 "	.cfi_adjust_cfa_offset -4\n"
    387 "	.cfi_restore %ebp\n"
    388 "	popl	%ebx\n"
    389 "	.cfi_adjust_cfa_offset -4\n"
    390 "	.cfi_restore %ebx\n"
    391 "	popl	%edi\n"
    392 "	.cfi_adjust_cfa_offset -4\n"
    393 "	.cfi_restore %edi\n"
    394 "	popl	%esi\n"
    395 "	.cfi_adjust_cfa_offset -4\n"
    396 "	.cfi_restore %esi\n"
    397 "	ret\n"
    398 "	.cfi_endproc\n"
    399 ".previous\n"
    400 );
    401 
    402 #elif defined(VGP_amd64_linux)
    403 /* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
    404    %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
    405    calling convention).
    406 
    407    The syscall number goes in %rax.  The args are passed to the syscall in
    408    the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
    409    ie. the kernel's syscall calling convention.
    410 
    411    %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
    412    no matter, they are caller-save (the syscall clobbers no callee-save
    413    regs, so we don't have to do any register saving/restoring).
    414 */
    415 extern UWord do_syscall_WRK (
    416           UWord syscall_no,
    417           UWord a1, UWord a2, UWord a3,
    418           UWord a4, UWord a5, UWord a6
    419        );
    420 asm(
    421 ".text\n"
    422 ".globl do_syscall_WRK\n"
    423 "do_syscall_WRK:\n"
    424         /* Convert function calling convention --> syscall calling
    425            convention */
    426 "	movq	%rdi, %rax\n"
    427 "	movq	%rsi, %rdi\n"
    428 "	movq	%rdx, %rsi\n"
    429 "	movq	%rcx, %rdx\n"
    430 "	movq	%r8,  %r10\n"
    431 "	movq	%r9,  %r8\n"
    432 "	movq    8(%rsp), %r9\n"	 /* last arg from stack */
    433 "	syscall\n"
    434 "	ret\n"
    435 ".previous\n"
    436 );
    437 
    438 #elif defined(VGP_ppc32_linux)
    439 /* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
    440 
    441    The syscall number goes in %r0.  The args are passed to the syscall in
    442    the regs %r3:%r8, i.e. the kernel's syscall calling convention.
    443 
    444    The %cr0.so bit flags an error.
    445    We return the syscall return value in %r3, and the %cr0.so in
    446    the lowest bit of %r4.
    447    We return a ULong, of which %r3 is the high word, and %r4 the low.
    448    No callee-save regs are clobbered, so no saving/restoring is needed.
    449 */
    450 extern ULong do_syscall_WRK (
    451           UWord syscall_no,
    452           UWord a1, UWord a2, UWord a3,
    453           UWord a4, UWord a5, UWord a6
    454        );
    455 asm(
    456 ".text\n"
    457 ".globl do_syscall_WRK\n"
    458 "do_syscall_WRK:\n"
    459 "        mr      0,3\n"
    460 "        mr      3,4\n"
    461 "        mr      4,5\n"
    462 "        mr      5,6\n"
    463 "        mr      6,7\n"
    464 "        mr      7,8\n"
    465 "        mr      8,9\n"
    466 "        sc\n"                  /* syscall: sets %cr0.so on error         */
    467 "        mfcr    4\n"           /* %cr -> low word of return var          */
    468 "        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
    469 "        blr\n"                 /* and return                             */
    470 ".previous\n"
    471 );
    472 
    473 #elif defined(VGP_ppc64be_linux)
    474 /* Due to the need to return 65 bits of result, this is completely
    475    different from the ppc32 case.  The single arg register points to a
    476    7-word block containing the syscall # and the 6 args.  The syscall
    477    result proper is put in [0] of the block, and %cr0.so is in the
    478    bottom bit of [1]. */
    479 extern void do_syscall_WRK ( ULong* argblock );
    480 asm(
    481 ".align   2\n"
    482 ".globl   do_syscall_WRK\n"
    483 ".section \".opd\",\"aw\"\n"
    484 ".align   3\n"
    485 "do_syscall_WRK:\n"
    486 ".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
    487 ".previous\n"
    488 ".type    .do_syscall_WRK,@function\n"
    489 ".globl   .do_syscall_WRK\n"
    490 ".do_syscall_WRK:\n"
    491 "        std  3,-16(1)\n"  /* stash arg */
    492 "        ld   8, 48(3)\n"  /* sc arg 6 */
    493 "        ld   7, 40(3)\n"  /* sc arg 5 */
    494 "        ld   6, 32(3)\n"  /* sc arg 4 */
    495 "        ld   5, 24(3)\n"  /* sc arg 3 */
    496 "        ld   4, 16(3)\n"  /* sc arg 2 */
    497 "        ld   0,  0(3)\n"  /* sc number */
    498 "        ld   3,  8(3)\n"  /* sc arg 1 */
    499 "        sc\n"             /* result in r3 and cr0.so */
    500 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
    501 "        std  3,0(5)\n"    /* argblock[0] = r3 */
    502 "        mfcr 3\n"
    503 "        srwi 3,3,28\n"
    504 "        andi. 3,3,1\n"
    505 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
    506 "        blr\n"
    507 );
    508 
    509 #elif defined(VGP_ppc64le_linux)
    510 /* Due to the need to return 65 bits of result, this is completely
    511    different from the ppc32 case.  The single arg register points to a
    512    7-word block containing the syscall # and the 6 args.  The syscall
    513    result proper is put in [0] of the block, and %cr0.so is in the
    514    bottom bit of [1]. */
    515 extern void do_syscall_WRK ( ULong* argblock );
    516 /* Little Endian supports ELF version 2.  In the future, it may support
    517  * other versions as well.
    518  */
    519 asm(
    520 ".align   2\n"
    521 ".globl   do_syscall_WRK\n"
    522 ".type    do_syscall_WRK,@function\n"
    523 "do_syscall_WRK:\n"
    524 "#if  _CALL_ELF == 2"               "\n"
    525 "0:      addis        2,12,.TOC.-0b@ha\n"
    526 "        addi         2,2,.TOC.-0b@l\n"
    527 "        .localentry do_syscall_WRK, .-do_syscall_WRK\n"
    528 "#endif"                            "\n"
    529 "        std  3,-16(1)\n"  /* stash arg */
    530 "        ld   8, 48(3)\n"  /* sc arg 6 */
    531 "        ld   7, 40(3)\n"  /* sc arg 5 */
    532 "        ld   6, 32(3)\n"  /* sc arg 4 */
    533 "        ld   5, 24(3)\n"  /* sc arg 3 */
    534 "        ld   4, 16(3)\n"  /* sc arg 2 */
    535 "        ld   0,  0(3)\n"  /* sc number */
    536 "        ld   3,  8(3)\n"  /* sc arg 1 */
    537 "        sc\n"             /* result in r3 and cr0.so */
    538 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
    539 "        std  3,0(5)\n"    /* argblock[0] = r3 */
    540 "        mfcr 3\n"
    541 "        srwi 3,3,28\n"
    542 "        andi. 3,3,1\n"
    543 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
    544 "        blr\n"
    545 "        .size do_syscall_WRK, .-do_syscall_WRK\n"
    546 );
    547 
    548 #elif defined(VGP_arm_linux)
    549 /* I think the conventions are:
    550    args  in r0 r1 r2 r3 r4 r5
    551    sysno in r7
    552    return value in r0, w/ same conventions as x86-linux, viz r0 in
    553    -4096 .. -1 is an error value.  All other values are success
    554    values.
    555 */
    556 extern UWord do_syscall_WRK (
    557           UWord a1, UWord a2, UWord a3,
    558           UWord a4, UWord a5, UWord a6,
    559           UWord syscall_no
    560        );
    561 asm(
    562 ".text\n"
    563 ".globl do_syscall_WRK\n"
    564 "do_syscall_WRK:\n"
    565 "         push    {r4, r5, r7}\n"
    566 "         ldr     r4, [sp, #12]\n"
    567 "         ldr     r5, [sp, #16]\n"
    568 "         ldr     r7, [sp, #20]\n"
    569 "         svc     0x0\n"
    570 "         pop     {r4, r5, r7}\n"
    571 "         bx      lr\n"
    572 ".previous\n"
    573 );
    574 
    575 #elif defined(VGP_arm64_linux)
    576 /* I think the conventions are:
    577    args  in r0 r1 r2 r3 r4 r5
    578    sysno in r8
    579    return value in r0, w/ same conventions as x86-linux, viz r0 in
    580    -4096 .. -1 is an error value.  All other values are success
    581    values.
    582 
    583    r0 to r5 remain unchanged, but syscall_no is in r6 and needs
    584    to be moved to r8 (??)
    585 */
    586 extern UWord do_syscall_WRK (
    587           UWord a1, UWord a2, UWord a3,
    588           UWord a4, UWord a5, UWord a6,
    589           UWord syscall_no
    590        );
    591 asm(
    592 ".text\n"
    593 ".globl do_syscall_WRK\n"
    594 "do_syscall_WRK:\n"
    595 "        mov x8, x6\n"
    596 "        mov x6, 0\n"
    597 "        mov x7, 0\n"
    598 "        svc 0\n"
    599 "        ret\n"
    600 ".previous\n"
    601 );
    602 
    603 #elif defined(VGP_x86_darwin)
    604 
    605 /* Incoming args (syscall number + up to 8 args) come in on the stack
    606 
    607    The kernel's syscall calling convention is:
    608    * the syscall number goes in eax
    609    * the args are passed to the syscall on the stack,
    610      pushed onto the stack R->L (that is, the usual x86
    611      calling conventions, with the leftmost arg at the lowest
    612      address)
    613    Call instruction:
    614    * UNIX: sysenter
    615    * UNIX: int $0x80
    616    * MACH: int $0x81
    617    * MDEP: int $0x82
    618    Note that the call type can be determined from the syscall number;
    619    there is no need to inspect the actual instruction.  Although obviously
    620    the instruction must match.
    621    Return value:
    622    * MACH,MDEP: the return value comes back in eax
    623    * UNIX: the return value comes back in edx:eax (hi32:lo32)
    624    Error:
    625    * MACH,MDEP: no error is returned
    626    * UNIX: the carry flag indicates success or failure
    627 
    628    nb here, sizeof(UWord) == sizeof(UInt)
    629 */
    630 
    631 __private_extern__ ULong
    632 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    633                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    634                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    635                       UWord syscall_no, /* 36(esp) */
    636                       /*OUT*/UInt* errflag /* 40(esp) */ );
    637 // Unix syscall: 64-bit return in edx:eax, with LSB in eax
    638 // error indicated by carry flag: clear=good, set=bad
    639 asm(".private_extern _do_syscall_unix_WRK\n"
    640     "_do_syscall_unix_WRK:\n"
    641     "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
    642     "        movl    $0, (%ecx)       \n"
    643     "        movl    36(%esp), %eax   \n"
    644     "        int     $0x80            \n"
    645     "        jnc     1f               \n"  /* jump if success */
    646     "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
    647     "        movl    $1, (%ecx)       \n"
    648     "    1:  ret                      \n"
    649     );
    650 
    651 __private_extern__ UInt
    652 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    653                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    654                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    655                       UWord syscall_no /* 36(esp) */ );
    656 // Mach trap: 32-bit result in %eax, no error flag
    657 asm(".private_extern _do_syscall_mach_WRK\n"
    658     "_do_syscall_mach_WRK:\n"
    659     "        movl    36(%esp), %eax   \n"
    660     "        int     $0x81            \n"
    661     "        ret                      \n"
    662     );
    663 
    664 __private_extern__ UInt
    665 do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
    666                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
    667                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
    668                       UWord syscall_no /* 36(esp) */ );
    669 // mdep trap: 32-bit result in %eax, no error flag
    670 asm(
    671     ".private_extern _do_syscall_mdep_WRK\n"
    672     "_do_syscall_mdep_WRK:\n"
    673     "        movl    36(%esp), %eax   \n"
    674     "        int     $0x82            \n"
    675     "        ret                      \n"
    676     );
    677 
    678 
    679 #elif defined(VGP_amd64_darwin)
    680 
    681 /* Incoming args (syscall number + up to 8 args) come in registers and stack
    682 
    683    The kernel's syscall calling convention is:
    684    * the syscall number goes in rax
    685    * the args are passed to the syscall in registers and the stack
    686    * the call instruction is 'syscall'
    687    Return value:
    688    * MACH,MDEP: the return value comes back in rax
    689    * UNIX: the return value comes back in rdx:rax (hi64:lo64)
    690    Error:
    691    * MACH,MDEP: no error is returned
    692    * UNIX: the carry flag indicates success or failure
    693 
    694    nb here, sizeof(UWord) == sizeof(ULong)
    695 */
    696 
    697 __private_extern__ UWord
    698 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    699                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    700                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    701                       UWord syscall_no,             /* 24(rsp) */
    702                       /*OUT*/ULong* errflag,        /* 32(rsp) */
    703                       /*OUT*/ULong* res2 );         /* 40(rsp) */
    704 // Unix syscall: 128-bit return in rax:rdx, with LSB in rax
    705 // error indicated by carry flag: clear=good, set=bad
    706 asm(".private_extern _do_syscall_unix_WRK\n"
    707     "_do_syscall_unix_WRK:\n"
    708     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    709     "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
    710     "        movq    $0, (%rax)       \n"
    711     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    712     "        syscall                  \n"
    713     "        jnc     1f               \n"  /* jump if success */
    714     "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
    715     "        movq    $1, (%rcx)       \n"
    716     "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
    717     "        movq    %rdx, (%rcx)     \n"
    718     "        retq                     \n"  /* return 1st result word */
    719     );
    720 
    721 __private_extern__ UWord
    722 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
    723                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
    724                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
    725                       UWord syscall_no );           /* 24(rsp) */
    726 // Mach trap: 64-bit result, no error flag
    727 asm(".private_extern _do_syscall_mach_WRK\n"
    728     "_do_syscall_mach_WRK:\n"
    729     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
    730     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
    731     "        syscall                  \n"
    732     "        retq                     \n"
    733     );
    734 
    735 #elif defined(VGP_s390x_linux)
    736 
    737 static UWord do_syscall_WRK (
    738    UWord syscall_no,
    739    UWord arg1, UWord arg2, UWord arg3,
    740    UWord arg4, UWord arg5, UWord arg6
    741    )
    742 {
    743    register UWord __arg1 asm("2") = arg1;
    744    register UWord __arg2 asm("3") = arg2;
    745    register UWord __arg3 asm("4") = arg3;
    746    register UWord __arg4 asm("5") = arg4;
    747    register UWord __arg5 asm("6") = arg5;
    748    register UWord __arg6 asm("7") = arg6;
    749    register ULong __svcres asm("2");
    750 
    751    __asm__ __volatile__ (
    752                  "lgr %%r1,%1\n\t"
    753                  "svc 0\n\t"
    754 		: "=d" (__svcres)
    755 		: "a" (syscall_no),
    756 		  "0" (__arg1),
    757 		  "d" (__arg2),
    758 		  "d" (__arg3),
    759 		  "d" (__arg4),
    760 		  "d" (__arg5),
    761 		  "d" (__arg6)
    762 		: "1", "cc", "memory");
    763 
    764    return (UWord) (__svcres);
    765 }
    766 
    767 #elif defined(VGP_mips32_linux)
    768 /* Incoming args (syscall number + up to 6 args) come in a0 - a3 and stack.
    769 
    770    The syscall number goes in v0.  The args are passed to the syscall in
    771    the regs a0 - a3 and stack, i.e. the kernel's syscall calling convention.
    772 
    773    (a3 != 0) flags an error.
    774    We return the syscall return value in v0.
    775    MIPS version
    776 */
    777 extern int do_syscall_WRK (
    778           int a1, int a2, int a3,
    779           int a4, int a5, int a6, int syscall_no, UWord *err,
    780           UWord *valHi, UWord* valLo
    781        );
    782 asm (
    783    ".text                                  \n\t"
    784    ".globl do_syscall_WRK                  \n\t"
    785    ".type  do_syscall_WRK, @function       \n\t"
    786    ".set push                              \n\t"
    787    ".set noreorder                         \n\t"
    788    "do_syscall_WRK:                        \n\t"
    789    "   lw $2, 24($29)                      \n\t"
    790    "   syscall                             \n\t"
    791    "   lw $8, 28($29)                      \n\t"
    792    "   sw $7, ($8)                         \n\t"
    793    "   lw $8, 32($29)                      \n\t"
    794    "   sw $3, ($8)                         \n\t" /* store valHi */
    795    "   lw $8, 36($29)                      \n\t"
    796    "   jr $31                              \n\t"
    797    "   sw $2, ($8)                         \n\t" /* store valLo */
    798    ".size do_syscall_WRK, .-do_syscall_WRK \n\t"
    799    ".set pop                               \n\t"
    800    ".previous                              \n\t"
    801 );
    802 
    803 #elif defined(VGP_mips64_linux)
    804 extern UWord do_syscall_WRK ( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5,
    805                               UWord a6, UWord syscall_no, ULong* V1_A3_val );
    806 asm (
    807    ".text                                  \n\t"
    808    ".globl do_syscall_WRK                  \n\t"
    809    ".type  do_syscall_WRK, @function       \n\t"
    810    ".set push                              \n\t"
    811    ".set noreorder                         \n\t"
    812    "do_syscall_WRK:                        \n\t"
    813    "   daddiu $29, $29, -8                 \n\t"
    814    "   sd $11, 0($29)                      \n\t"
    815    "   move $2, $10                        \n\t"
    816    "   syscall                             \n\t"
    817    "   ld $11, 0($29)                      \n\t"
    818    "   daddiu $29, $29, 8                  \n\t"
    819    "   sd $3, 0($11)                       \n\t" /* store v1 in last param */
    820    "   jr $31                              \n\t"
    821    "   sd $7, 8($11)                       \n\t" /* store a3 in last param */
    822    ".size do_syscall_WRK, .-do_syscall_WRK \n\t"
    823    ".set pop                               \n\t"
    824    ".previous                              \n\t"
    825 );
    826 
    827 #elif defined(VGP_x86_solaris)
    828 
    829 extern ULong
    830 do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* 4(esp)..12(esp) */
    831                UWord a4, UWord a5, UWord a6,    /* 16(esp)..24(esp) */
    832                UWord a7, UWord a8,              /* 28(esp)..32(esp) */
    833                UWord syscall_no,                /* 36(esp) */
    834                /*OUT*/UInt *errflag);           /* 40(esp) */
    835 /* Classic unix syscall.. parameters on the stack, an unused (by the kernel)
    836    return address at 0(esp), a sysno in eax, a result in edx:eax, the carry
    837    flag set on error. */
    838 __asm__ (
    839 ".text\n"
    840 ".globl do_syscall_WRK\n"
    841 "do_syscall_WRK:\n"
    842 "       movl    40(%esp), %ecx\n"       /* assume syscall success */
    843 "       movl    $0, (%ecx)\n"
    844 "       movl    36(%esp), %eax\n"
    845 "       int     $0x91\n"
    846 "       jnc     1f\n"                   /* jump if success */
    847 "       movl    40(%esp), %ecx\n"       /* syscall failed - set *errflag */
    848 "       movl    $1, (%ecx)\n"
    849 "1:     ret\n"
    850 ".previous\n"
    851 );
    852 
    853 extern ULong
    854 do_syscall_fast_WRK(UWord syscall_no);          /* 4(esp) */
    855 /* Fasttrap syscall.. no parameters, a sysno in eax, a result in edx:eax,
    856    never fails (if the sysno is valid). */
    857 __asm__ (
    858 ".text\n"
    859 ".globl do_syscall_fast_WRK\n"
    860 "do_syscall_fast_WRK:\n"
    861 "       movl    4(%esp), %eax\n"
    862 "       int     $0xD2\n"
    863 "       ret\n"
    864 ".previous\n"
    865 );
    866 
    867 #elif defined(VGP_amd64_solaris)
    868 
    869 extern ULong
    870 do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* rdi, rsi, rdx */
    871                UWord a4, UWord a5, UWord a6,    /* rcx, r8, r9 */
    872                UWord a7, UWord a8,              /* 8(rsp), 16(rsp) */
    873                UWord syscall_no,                /* 24(rsp) */
    874                /*OUT*/ULong *errflag,           /* 32(rsp) */
    875                /*OUT*/ULong *res2);             /* 40(rsp) */
    876 /* First 6 parameters in registers rdi, rsi, rdx, r10, r8, r9, next
    877    2 parameters on the stack, an unused (by the kernel) return address at
    878    0(rsp), a sysno in rax, a result in rdx:rax, the carry flag set on
    879    error. */
    880 __asm__ (
    881 ".text\n"
    882 ".globl do_syscall_WRK\n"
    883 "do_syscall_WRK:\n"
    884 "       movq    %rcx, %r10\n"           /* pass rcx in r10 instead */
    885 "       movq    32(%rsp), %rcx\n"       /* assume syscall success */
    886 "       movq    $0, (%rcx)\n"
    887 "       movq    24(%rsp), %rax\n"
    888 "       syscall\n"
    889 "       jnc     1f\n"                   /* jump if success */
    890 "       movq    32(%rsp), %rcx\n"       /* syscall failed - set *errflag */
    891 "       movq    $1, (%rcx)\n"
    892 "1:     movq    40(%rsp), %rcx\n"       /* save 2nd result word */
    893 "       movq    %rdx, (%rcx)\n"
    894 "       ret\n"
    895 ".previous\n"
    896 );
    897 
    898 extern ULong
    899 do_syscall_fast_WRK(UWord syscall_no,           /* rdi */
    900                     /*OUT*/ULong *res2);        /* rsi */
    901 /* Fasttrap syscall.. no parameters, a sysno in rax, a result in rdx:rax,
    902    never fails (if the sysno is valid). */
    903 __asm__ (
    904 ".text\n"
    905 ".globl do_syscall_fast_WRK\n"
    906 "do_syscall_fast_WRK:\n"
    907 "       movq    %rdi, %rax\n"
    908 "       int     $0xD2\n"
    909 "       movq    %rdx, (%rsi)\n"         /* save 2nd result word */
    910 "       ret\n"
    911 ".previous\n"
    912 );
    913 
    914 #else
    915 #  error Unknown platform
    916 #endif
    917 
    918 
    919 /* Finally, the generic code.  This sends the call to the right
    920    helper. */
    921 
    922 SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
    923                                       UWord a4, UWord a5, UWord a6,
    924                                       UWord a7, UWord a8 )
    925 {
    926 #  if defined(VGP_x86_linux)
    927    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    928    return VG_(mk_SysRes_x86_linux)( val );
    929 
    930 #  elif defined(VGP_amd64_linux)
    931    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    932    return VG_(mk_SysRes_amd64_linux)( val );
    933 
    934 #  elif defined(VGP_ppc32_linux)
    935    ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
    936    UInt  val     = (UInt)(ret>>32);
    937    UInt  cr0so   = (UInt)(ret);
    938    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
    939 
    940 #  elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
    941    ULong argblock[7];
    942    argblock[0] = sysno;
    943    argblock[1] = a1;
    944    argblock[2] = a2;
    945    argblock[3] = a3;
    946    argblock[4] = a4;
    947    argblock[5] = a5;
    948    argblock[6] = a6;
    949    do_syscall_WRK( &argblock[0] );
    950    return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
    951 
    952 #  elif defined(VGP_arm_linux)
    953    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
    954    return VG_(mk_SysRes_arm_linux)( val );
    955 
    956 #  elif defined(VGP_arm64_linux)
    957    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
    958    return VG_(mk_SysRes_arm64_linux)( val );
    959 
    960 #  elif defined(VGP_x86_darwin)
    961    UInt  wLO = 0, wHI = 0, err = 0;
    962    ULong u64;
    963    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    964    switch (scclass) {
    965       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    966          u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    967                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
    968          wLO = (UInt)u64;
    969          wHI = (UInt)(u64 >> 32);
    970          break;
    971       case VG_DARWIN_SYSCALL_CLASS_MACH:
    972          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    973                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    974          err = 0;
    975          break;
    976       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    977          wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    978                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    979          err = 0;
    980          break;
    981       default:
    982          vg_assert(0);
    983          break;
    984    }
    985    return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
    986 
    987 #  elif defined(VGP_amd64_darwin)
    988    ULong wLO = 0, wHI = 0, err = 0;
    989    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
    990    switch (scclass) {
    991       case VG_DARWIN_SYSCALL_CLASS_UNIX:
    992          wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    993                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
    994          break;
    995       case VG_DARWIN_SYSCALL_CLASS_MACH:
    996       case VG_DARWIN_SYSCALL_CLASS_MDEP:
    997          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
    998                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
    999          err = 0;
   1000          break;
   1001       default:
   1002          vg_assert(0);
   1003          break;
   1004    }
   1005    return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
   1006 
   1007 #elif defined(VGP_s390x_linux)
   1008    UWord val;
   1009 
   1010    if (sysno == __NR_mmap) {
   1011      ULong argbuf[6];
   1012 
   1013      argbuf[0] = a1;
   1014      argbuf[1] = a2;
   1015      argbuf[2] = a3;
   1016      argbuf[3] = a4;
   1017      argbuf[4] = a5;
   1018      argbuf[5] = a6;
   1019      val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
   1020    } else {
   1021      val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
   1022    }
   1023 
   1024    return VG_(mk_SysRes_s390x_linux)( val );
   1025 
   1026 #elif defined(VGP_mips32_linux)
   1027    UWord err   = 0;
   1028    UWord valHi = 0;
   1029    UWord valLo = 0;
   1030    (void) do_syscall_WRK(a1,a2,a3,a4,a5,a6, sysno,&err,&valHi,&valLo);
   1031    return VG_(mk_SysRes_mips32_linux)( valLo, valHi, (ULong)err );
   1032 
   1033 #elif defined(VGP_mips64_linux)
   1034    ULong v1_a3[2];
   1035    v1_a3[0] = 0xFF00;
   1036    v1_a3[1] = 0xFF00;
   1037    ULong V0 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno,v1_a3);
   1038    ULong V1 = (ULong)v1_a3[0];
   1039    ULong A3 = (ULong)v1_a3[1];
   1040    return VG_(mk_SysRes_mips64_linux)( V0, V1, A3 );
   1041 
   1042 #  elif defined(VGP_x86_solaris)
   1043    UInt val, val2, err = False;
   1044    Bool restart;
   1045    ULong u64;
   1046    UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
   1047 
   1048    switch (ssclass) {
   1049       case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
   1050          /* The Solaris kernel does not restart syscalls automatically so it
   1051             is done here. */
   1052          do {
   1053             u64 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
   1054                                  VG_SOLARIS_SYSNO_INDEX(sysno), &err);
   1055             val = (UInt)u64;
   1056             restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
   1057          } while (restart);
   1058          break;
   1059       case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
   1060          u64 = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno));
   1061          break;
   1062       default:
   1063          vg_assert(0);
   1064          break;
   1065    }
   1066 
   1067    val = (UInt)u64;
   1068    val2 = (UInt)(u64 >> 32);
   1069    return VG_(mk_SysRes_x86_solaris)(err ? True : False, val,
   1070                                      err ? 0 : val2);
   1071 
   1072 #  elif defined(VGP_amd64_solaris)
   1073    ULong val, val2, err = False;
   1074    Bool restart;
   1075    UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
   1076 
   1077    switch (ssclass) {
   1078       case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
   1079          /* The Solaris kernel does not restart syscalls automatically so it
   1080             is done here. */
   1081          do {
   1082             val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
   1083                                  VG_SOLARIS_SYSNO_INDEX(sysno), &err, &val2);
   1084             restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
   1085          } while (restart);
   1086          break;
   1087       case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
   1088          val = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno), &val2);
   1089          break;
   1090       default:
   1091          vg_assert(0);
   1092          break;
   1093    }
   1094 
   1095    return VG_(mk_SysRes_amd64_solaris)(err ? True : False, val,
   1096                                        err ? 0 : val2);
   1097 
   1098 #else
   1099 #  error Unknown platform
   1100 #endif
   1101 }
   1102 
   1103 /* ---------------------------------------------------------------------
   1104    Names of errors.
   1105    ------------------------------------------------------------------ */
   1106 
   1107 /* Return a string which gives the name of an error value.  Note,
   1108    unlike the standard C syserror fn, the returned string is not
   1109    malloc-allocated or writable -- treat it as a constant.
   1110    TODO: implement this properly. */
   1111 
   1112 const HChar* VG_(strerror) ( UWord errnum )
   1113 {
   1114    switch (errnum) {
   1115    case VKI_EPERM:       return "Operation not permitted";
   1116    case VKI_ENOENT:      return "No such file or directory";
   1117    case VKI_ESRCH:       return "No such process";
   1118    case VKI_EINTR:       return "Interrupted system call";
   1119    case VKI_EIO:         return "Input/output error";
   1120    case VKI_ENXIO:       return "No such device or address";
   1121    case VKI_E2BIG:       return "Argument list too long";
   1122    case VKI_ENOEXEC:     return "Exec format error";
   1123    case VKI_EBADF:       return "Bad file descriptor";
   1124    case VKI_ECHILD:      return "No child processes";
   1125    case VKI_EAGAIN:      return "Resource temporarily unavailable";
   1126    case VKI_ENOMEM:      return "Cannot allocate memory";
   1127    case VKI_EACCES:      return "Permission denied";
   1128    case VKI_EFAULT:      return "Bad address";
   1129    case VKI_ENOTBLK:     return "Block device required";
   1130    case VKI_EBUSY:       return "Device or resource busy";
   1131    case VKI_EEXIST:      return "File exists";
   1132    case VKI_EXDEV:       return "Invalid cross-device link";
   1133    case VKI_ENODEV:      return "No such device";
   1134    case VKI_ENOTDIR:     return "Not a directory";
   1135    case VKI_EISDIR:      return "Is a directory";
   1136    case VKI_EINVAL:      return "Invalid argument";
   1137    case VKI_ENFILE:      return "Too many open files in system";
   1138    case VKI_EMFILE:      return "Too many open files";
   1139    case VKI_ENOTTY:      return "Inappropriate ioctl for device";
   1140    case VKI_ETXTBSY:     return "Text file busy";
   1141    case VKI_EFBIG:       return "File too large";
   1142    case VKI_ENOSPC:      return "No space left on device";
   1143    case VKI_ESPIPE:      return "Illegal seek";
   1144    case VKI_EROFS:       return "Read-only file system";
   1145    case VKI_EMLINK:      return "Too many links";
   1146    case VKI_EPIPE:       return "Broken pipe";
   1147    case VKI_EDOM:        return "Numerical argument out of domain";
   1148    case VKI_ERANGE:      return "Numerical result out of range";
   1149 
   1150    case VKI_ENOSYS:      return "Function not implemented";
   1151    case VKI_EOVERFLOW:   return "Value too large for defined data type";
   1152 #     if defined(VKI_ERESTARTSYS)
   1153       case VKI_ERESTARTSYS: return "ERESTARTSYS";
   1154 #     endif
   1155    default:              return "VG_(strerror): unknown error";
   1156    }
   1157 }
   1158 
   1159 
   1160 /*--------------------------------------------------------------------*/
   1161 /*--- end                                                          ---*/
   1162 /*--------------------------------------------------------------------*/
   1163