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