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@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 
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 */
VG_(mk_SysRes_ppc32_linux)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 */
VG_(mk_SysRes_ppc64_linux)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 
VG_(mk_SysRes_s390x_linux)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 
VG_(mk_SysRes_arm_linux)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 
VG_(mk_SysRes_arm64_linux)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. */
VG_(mk_SysRes_Error)185 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
186    SysRes r;
187    r._isError = True;
188    r._val     = err;
189    return r;
190 }
191 
VG_(mk_SysRes_Success)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. */
VG_(mk_SysRes_x86_darwin)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 
VG_(mk_SysRes_amd64_darwin)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. */
VG_(mk_SysRes_Error)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 
VG_(mk_SysRes_Success)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. */
VG_(mk_SysRes_Error)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 
VG_(mk_SysRes_Success)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 
VG_(mk_SysRes_x86_solaris)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 
VG_(mk_SysRes_amd64_solaris)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 
335 #elif defined(VGO_dragonfly)
336 
VG_(mk_SysRes_x86_dragonfly)337 SysRes VG_(mk_SysRes_x86_dragonfly) ( UInt val, UInt val2, Bool err ) {
338    SysRes r;
339    r._isError = err;
340    r._val = val;
341    r._val2 = val2;
342    return r;
343 }
344 
VG_(mk_SysRes_amd64_dragonfly)345 SysRes VG_(mk_SysRes_amd64_dragonfly) ( ULong val, ULong val2, Bool err ) {
346    SysRes r;
347    r._isError = err;
348    r._val = val;
349    r._val2 = val2;
350    return r;
351 }
352 
353 /* Generic constructors. */
VG_(mk_SysRes_Error)354 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
355    SysRes r;
356    r._val     = err;
357    r._val2    = 0;
358    r._isError = True;
359    return r;
360 }
361 
VG_(mk_SysRes_Success)362 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
363    SysRes r;
364    r._val     = res;
365    r._val2    = 0;
366    r._isError = False;
367    return r;
368 }
369 
370 #else
371 #  error "Unknown OS"
372 #endif
373 
374 
375 /* ---------------------------------------------------------------------
376    VG_(do_syscall): A function for doing syscalls.
377    ------------------------------------------------------------------ */
378 
379 #if defined(VGP_x86_linux)
380 /* Incoming args (syscall number + up to 6 args) come on the stack.
381    (ie. the C calling convention).
382 
383    The syscall number goes in %eax.  The args are passed to the syscall in
384    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
385    calling convention.
386 
387    %eax gets the return value.  Not sure which registers the kernel
388    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
389    %ebp).
390 */
391 extern UWord do_syscall_WRK (
392           UWord syscall_no,
393           UWord a1, UWord a2, UWord a3,
394           UWord a4, UWord a5, UWord a6
395        );
396 asm(
397 ".text\n"
398 ".globl do_syscall_WRK\n"
399 "do_syscall_WRK:\n"
400 "	.cfi_startproc\n"
401 "	push	%esi\n"
402 "	.cfi_adjust_cfa_offset 4\n"
403 "	.cfi_offset %esi, -8\n"
404 "	push	%edi\n"
405 "	.cfi_adjust_cfa_offset 4\n"
406 "	.cfi_offset %edi, -12\n"
407 "	push	%ebx\n"
408 "	.cfi_adjust_cfa_offset 4\n"
409 "	.cfi_offset %ebx, -16\n"
410 "	push	%ebp\n"
411 "	.cfi_adjust_cfa_offset 4\n"
412 "	.cfi_offset %ebp, -20\n"
413 "	movl	16+ 4(%esp),%eax\n"
414 "	movl	16+ 8(%esp),%ebx\n"
415 "	movl	16+12(%esp),%ecx\n"
416 "	movl	16+16(%esp),%edx\n"
417 "	movl	16+20(%esp),%esi\n"
418 "	movl	16+24(%esp),%edi\n"
419 "	movl	16+28(%esp),%ebp\n"
420 "	int	$0x80\n"
421 "	popl	%ebp\n"
422 "	.cfi_adjust_cfa_offset -4\n"
423 "	.cfi_restore %ebp\n"
424 "	popl	%ebx\n"
425 "	.cfi_adjust_cfa_offset -4\n"
426 "	.cfi_restore %ebx\n"
427 "	popl	%edi\n"
428 "	.cfi_adjust_cfa_offset -4\n"
429 "	.cfi_restore %edi\n"
430 "	popl	%esi\n"
431 "	.cfi_adjust_cfa_offset -4\n"
432 "	.cfi_restore %esi\n"
433 "	ret\n"
434 "	.cfi_endproc\n"
435 ".previous\n"
436 );
437 
438 #elif defined(VGP_amd64_linux)
439 /* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
440    %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
441    calling convention).
442 
443    The syscall number goes in %rax.  The args are passed to the syscall in
444    the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
445    ie. the kernel's syscall calling convention.
446 
447    %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
448    no matter, they are caller-save (the syscall clobbers no callee-save
449    regs, so we don't have to do any register saving/restoring).
450 */
451 extern UWord do_syscall_WRK (
452           UWord syscall_no,
453           UWord a1, UWord a2, UWord a3,
454           UWord a4, UWord a5, UWord a6
455        );
456 asm(
457 ".text\n"
458 ".globl do_syscall_WRK\n"
459 "do_syscall_WRK:\n"
460         /* Convert function calling convention --> syscall calling
461            convention */
462 "	movq	%rdi, %rax\n"
463 "	movq	%rsi, %rdi\n"
464 "	movq	%rdx, %rsi\n"
465 "	movq	%rcx, %rdx\n"
466 "	movq	%r8,  %r10\n"
467 "	movq	%r9,  %r8\n"
468 "	movq    8(%rsp), %r9\n"	 /* last arg from stack */
469 "	syscall\n"
470 "	ret\n"
471 ".previous\n"
472 );
473 
474 #elif defined(VGP_ppc32_linux)
475 /* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
476 
477    The syscall number goes in %r0.  The args are passed to the syscall in
478    the regs %r3:%r8, i.e. the kernel's syscall calling convention.
479 
480    The %cr0.so bit flags an error.
481    We return the syscall return value in %r3, and the %cr0.so in
482    the lowest bit of %r4.
483    We return a ULong, of which %r3 is the high word, and %r4 the low.
484    No callee-save regs are clobbered, so no saving/restoring is needed.
485 */
486 extern ULong do_syscall_WRK (
487           UWord syscall_no,
488           UWord a1, UWord a2, UWord a3,
489           UWord a4, UWord a5, UWord a6
490        );
491 asm(
492 ".text\n"
493 ".globl do_syscall_WRK\n"
494 "do_syscall_WRK:\n"
495 "        mr      0,3\n"
496 "        mr      3,4\n"
497 "        mr      4,5\n"
498 "        mr      5,6\n"
499 "        mr      6,7\n"
500 "        mr      7,8\n"
501 "        mr      8,9\n"
502 "        sc\n"                  /* syscall: sets %cr0.so on error         */
503 "        mfcr    4\n"           /* %cr -> low word of return var          */
504 "        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
505 "        blr\n"                 /* and return                             */
506 ".previous\n"
507 );
508 
509 #elif defined(VGP_ppc64be_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 asm(
517 ".align   2\n"
518 ".globl   do_syscall_WRK\n"
519 ".section \".opd\",\"aw\"\n"
520 ".align   3\n"
521 "do_syscall_WRK:\n"
522 ".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
523 ".previous\n"
524 ".type    .do_syscall_WRK,@function\n"
525 ".globl   .do_syscall_WRK\n"
526 ".do_syscall_WRK:\n"
527 "        std  3,-16(1)\n"  /* stash arg */
528 "        ld   8, 48(3)\n"  /* sc arg 6 */
529 "        ld   7, 40(3)\n"  /* sc arg 5 */
530 "        ld   6, 32(3)\n"  /* sc arg 4 */
531 "        ld   5, 24(3)\n"  /* sc arg 3 */
532 "        ld   4, 16(3)\n"  /* sc arg 2 */
533 "        ld   0,  0(3)\n"  /* sc number */
534 "        ld   3,  8(3)\n"  /* sc arg 1 */
535 "        sc\n"             /* result in r3 and cr0.so */
536 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
537 "        std  3,0(5)\n"    /* argblock[0] = r3 */
538 "        mfcr 3\n"
539 "        srwi 3,3,28\n"
540 "        andi. 3,3,1\n"
541 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
542 "        blr\n"
543 );
544 
545 #elif defined(VGP_ppc64le_linux)
546 /* Due to the need to return 65 bits of result, this is completely
547    different from the ppc32 case.  The single arg register points to a
548    7-word block containing the syscall # and the 6 args.  The syscall
549    result proper is put in [0] of the block, and %cr0.so is in the
550    bottom bit of [1]. */
551 extern void do_syscall_WRK ( ULong* argblock );
552 /* Little Endian supports ELF version 2.  In the future, it may support
553  * other versions as well.
554  */
555 asm(
556 ".align   2\n"
557 ".globl   do_syscall_WRK\n"
558 ".type    do_syscall_WRK,@function\n"
559 "do_syscall_WRK:\n"
560 "#if  _CALL_ELF == 2"               "\n"
561 "0:      addis        2,12,.TOC.-0b@ha\n"
562 "        addi         2,2,.TOC.-0b@l\n"
563 "        .localentry do_syscall_WRK, .-do_syscall_WRK\n"
564 "#endif"                            "\n"
565 "        std  3,-16(1)\n"  /* stash arg */
566 "        ld   8, 48(3)\n"  /* sc arg 6 */
567 "        ld   7, 40(3)\n"  /* sc arg 5 */
568 "        ld   6, 32(3)\n"  /* sc arg 4 */
569 "        ld   5, 24(3)\n"  /* sc arg 3 */
570 "        ld   4, 16(3)\n"  /* sc arg 2 */
571 "        ld   0,  0(3)\n"  /* sc number */
572 "        ld   3,  8(3)\n"  /* sc arg 1 */
573 "        sc\n"             /* result in r3 and cr0.so */
574 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
575 "        std  3,0(5)\n"    /* argblock[0] = r3 */
576 "        mfcr 3\n"
577 "        srwi 3,3,28\n"
578 "        andi. 3,3,1\n"
579 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
580 "        blr\n"
581 "        .size do_syscall_WRK, .-do_syscall_WRK\n"
582 );
583 
584 #elif defined(VGP_arm_linux)
585 /* I think the conventions are:
586    args  in r0 r1 r2 r3 r4 r5
587    sysno in r7
588    return value in r0, w/ same conventions as x86-linux, viz r0 in
589    -4096 .. -1 is an error value.  All other values are success
590    values.
591 */
592 extern UWord do_syscall_WRK (
593           UWord a1, UWord a2, UWord a3,
594           UWord a4, UWord a5, UWord a6,
595           UWord syscall_no
596        );
597 asm(
598 ".text\n"
599 ".globl do_syscall_WRK\n"
600 "do_syscall_WRK:\n"
601 "         push    {r4, r5, r7}\n"
602 "         ldr     r4, [sp, #12]\n"
603 "         ldr     r5, [sp, #16]\n"
604 "         ldr     r7, [sp, #20]\n"
605 "         svc     0x0\n"
606 "         pop     {r4, r5, r7}\n"
607 "         bx      lr\n"
608 ".previous\n"
609 );
610 
611 #elif defined(VGP_arm64_linux)
612 /* I think the conventions are:
613    args  in r0 r1 r2 r3 r4 r5
614    sysno in r8
615    return value in r0, w/ same conventions as x86-linux, viz r0 in
616    -4096 .. -1 is an error value.  All other values are success
617    values.
618 
619    r0 to r5 remain unchanged, but syscall_no is in r6 and needs
620    to be moved to r8 (??)
621 */
622 extern UWord do_syscall_WRK (
623           UWord a1, UWord a2, UWord a3,
624           UWord a4, UWord a5, UWord a6,
625           UWord syscall_no
626        );
627 asm(
628 ".text\n"
629 ".globl do_syscall_WRK\n"
630 "do_syscall_WRK:\n"
631 "        mov x8, x6\n"
632 "        mov x6, 0\n"
633 "        mov x7, 0\n"
634 "        svc 0\n"
635 "        ret\n"
636 ".previous\n"
637 );
638 
639 #elif defined(VGP_x86_dragonfly)
640 /* Incoming args (syscall number + up to 8 args) are on the stack.
641    Dragonfly has a syscall called 'syscall' that takes all args (including
642    the syscall number) off the stack.  Since we're called, the return
643    address is on the stack as expected, so we can just call syscall(2)
644    and it Just Works.  Error is when carry is set.
645 */
646 extern ULong do_syscall_WRK (
647           UWord syscall_no,
648           UWord a1, UWord a2, UWord a3,
649           UWord a4, UWord a5, UWord a6,
650           UWord a7, UWord a8, UInt *flags
651        );
652 asm(
653 ".text\n"
654 "do_syscall_WRK:\n"
655 "      movl    $0,%eax\n"      /* syscall number = "syscall" (0) to avoid stack frobbing
656 */
657 "      int     $0x80\n"
658 "      jb      1f\n"
659 "      ret\n"
660 "1:    movl    40(%esp),%ecx\n"        /* store carry in *flags */
661 "      movl    $1,(%ecx)\n"
662 "      ret\n"
663 ".previous\n"
664 );
665 
666 #elif defined(VGP_amd64_dragonfly)
667 extern UWord do_syscall_WRK (
668           UWord syscall_no,    /* %rdi */
669           UWord a1,            /* %rsi */
670           UWord a2,            /* %rdx */
671           UWord a3,            /* %rcx */
672           UWord a4,            /* %r8 */
673           UWord a5,            /* %r9 */
674           UWord a6,            /* 8(%rsp) */
675           UWord a7,            /* 16(%rsp) */
676           UWord a8,            /* 24(%rsp) */
677           UInt *flags,         /* 32(%rsp) */
678           UWord *rv2           /* 40(%rsp) */
679        );
680 asm(
681 ".text\n"
682 "do_syscall_WRK:\n"
683         /* Convert function calling convention --> syscall calling
684            convention */
685 "      pushq   %rbp\n"
686 "      movq    %rsp, %rbp\n"
687 "      movq    %rdi, %rax\n"    /* syscall_no */
688 "      movq    %rsi, %rdi\n"    /* a1 */
689 "      movq    %rdx, %rsi\n"    /* a2 */
690 "      movq    %rcx, %rdx\n"    /* a3 */
691 "      movq    %r8,  %r10\n"    /* a4 */
692 "      movq    %r9,  %r8\n"     /* a5 */
693 "      movq    16(%rbp), %r9\n"  /* a6 last arg from stack, account for %rbp */
694 "      movq    24(%rbp), %r11\n" /* a7 from stack */
695 "      pushq  %r11\n"
696 "      movq    32(%rbp), %r11\n" /* a8 from stack */
697 "      pushq  %r11\n"
698 "      subq    $8,%rsp\n"      /* fake return addr */
699 "      syscall\n"
700 "      jb      1f\n"
701 "      movq    48(%rbp),%rsi\n"
702 "      movq    %rdx, (%rsi)\n"
703 "      movq    %rbp, %rsp\n"
704 "      popq    %rbp\n"
705 "      ret\n"
706 "1:\n"
707 "      movq    40(%rbp), %rsi\n"
708 "      movl    $1,(%rsi)\n"
709 "      movq    %rbp, %rsp\n"
710 "      popq    %rbp\n"
711 "      ret\n"
712 ".previous\n"
713 );
714 
715 #elif defined(VGP_x86_darwin)
716 
717 /* Incoming args (syscall number + up to 8 args) come in on the stack
718 
719    The kernel's syscall calling convention is:
720    * the syscall number goes in eax
721    * the args are passed to the syscall on the stack,
722      pushed onto the stack R->L (that is, the usual x86
723      calling conventions, with the leftmost arg at the lowest
724      address)
725    Call instruction:
726    * UNIX: sysenter
727    * UNIX: int $0x80
728    * MACH: int $0x81
729    * MDEP: int $0x82
730    Note that the call type can be determined from the syscall number;
731    there is no need to inspect the actual instruction.  Although obviously
732    the instruction must match.
733    Return value:
734    * MACH,MDEP: the return value comes back in eax
735    * UNIX: the return value comes back in edx:eax (hi32:lo32)
736    Error:
737    * MACH,MDEP: no error is returned
738    * UNIX: the carry flag indicates success or failure
739 
740    nb here, sizeof(UWord) == sizeof(UInt)
741 */
742 
743 __private_extern__ ULong
744 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
745                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
746                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
747                       UWord syscall_no, /* 36(esp) */
748                       /*OUT*/UInt* errflag /* 40(esp) */ );
749 // Unix syscall: 64-bit return in edx:eax, with LSB in eax
750 // error indicated by carry flag: clear=good, set=bad
751 asm(".private_extern _do_syscall_unix_WRK\n"
752     "_do_syscall_unix_WRK:\n"
753     "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
754     "        movl    $0, (%ecx)       \n"
755     "        movl    36(%esp), %eax   \n"
756     "        int     $0x80            \n"
757     "        jnc     1f               \n"  /* jump if success */
758     "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
759     "        movl    $1, (%ecx)       \n"
760     "    1:  ret                      \n"
761     );
762 
763 __private_extern__ UInt
764 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
765                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
766                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
767                       UWord syscall_no /* 36(esp) */ );
768 // Mach trap: 32-bit result in %eax, no error flag
769 asm(".private_extern _do_syscall_mach_WRK\n"
770     "_do_syscall_mach_WRK:\n"
771     "        movl    36(%esp), %eax   \n"
772     "        int     $0x81            \n"
773     "        ret                      \n"
774     );
775 
776 __private_extern__ UInt
777 do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
778                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
779                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
780                       UWord syscall_no /* 36(esp) */ );
781 // mdep trap: 32-bit result in %eax, no error flag
782 asm(
783     ".private_extern _do_syscall_mdep_WRK\n"
784     "_do_syscall_mdep_WRK:\n"
785     "        movl    36(%esp), %eax   \n"
786     "        int     $0x82            \n"
787     "        ret                      \n"
788     );
789 
790 
791 #elif defined(VGP_amd64_darwin)
792 
793 /* Incoming args (syscall number + up to 8 args) come in registers and stack
794 
795    The kernel's syscall calling convention is:
796    * the syscall number goes in rax
797    * the args are passed to the syscall in registers and the stack
798    * the call instruction is 'syscall'
799    Return value:
800    * MACH,MDEP: the return value comes back in rax
801    * UNIX: the return value comes back in rdx:rax (hi64:lo64)
802    Error:
803    * MACH,MDEP: no error is returned
804    * UNIX: the carry flag indicates success or failure
805 
806    nb here, sizeof(UWord) == sizeof(ULong)
807 */
808 
809 __private_extern__ UWord
810 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
811                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
812                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
813                       UWord syscall_no,             /* 24(rsp) */
814                       /*OUT*/ULong* errflag,        /* 32(rsp) */
815                       /*OUT*/ULong* res2 );         /* 40(rsp) */
816 // Unix syscall: 128-bit return in rax:rdx, with LSB in rax
817 // error indicated by carry flag: clear=good, set=bad
818 asm(".private_extern _do_syscall_unix_WRK\n"
819     "_do_syscall_unix_WRK:\n"
820     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
821     "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
822     "        movq    $0, (%rax)       \n"
823     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
824     "        syscall                  \n"
825     "        jnc     1f               \n"  /* jump if success */
826     "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
827     "        movq    $1, (%rcx)       \n"
828     "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
829     "        movq    %rdx, (%rcx)     \n"
830     "        retq                     \n"  /* return 1st result word */
831     );
832 
833 __private_extern__ UWord
834 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
835                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
836                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
837                       UWord syscall_no );           /* 24(rsp) */
838 // Mach trap: 64-bit result, no error flag
839 asm(".private_extern _do_syscall_mach_WRK\n"
840     "_do_syscall_mach_WRK:\n"
841     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
842     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
843     "        syscall                  \n"
844     "        retq                     \n"
845     );
846 
847 #elif defined(VGP_s390x_linux)
848 
do_syscall_WRK(UWord syscall_no,UWord arg1,UWord arg2,UWord arg3,UWord arg4,UWord arg5,UWord arg6)849 static UWord do_syscall_WRK (
850    UWord syscall_no,
851    UWord arg1, UWord arg2, UWord arg3,
852    UWord arg4, UWord arg5, UWord arg6
853    )
854 {
855    register UWord __arg1 asm("2") = arg1;
856    register UWord __arg2 asm("3") = arg2;
857    register UWord __arg3 asm("4") = arg3;
858    register UWord __arg4 asm("5") = arg4;
859    register UWord __arg5 asm("6") = arg5;
860    register UWord __arg6 asm("7") = arg6;
861    register ULong __svcres asm("2");
862 
863    __asm__ __volatile__ (
864                  "lgr %%r1,%1\n\t"
865                  "svc 0\n\t"
866 		: "=d" (__svcres)
867 		: "a" (syscall_no),
868 		  "0" (__arg1),
869 		  "d" (__arg2),
870 		  "d" (__arg3),
871 		  "d" (__arg4),
872 		  "d" (__arg5),
873 		  "d" (__arg6)
874 		: "1", "cc", "memory");
875 
876    return (UWord) (__svcres);
877 }
878 
879 #elif defined(VGP_mips32_linux)
880 /* Incoming args (syscall number + up to 6 args) come in a0 - a3 and stack.
881 
882    The syscall number goes in v0.  The args are passed to the syscall in
883    the regs a0 - a3 and stack, i.e. the kernel's syscall calling convention.
884 
885    (a3 != 0) flags an error.
886    We return the syscall return value in v0.
887    MIPS version
888 */
889 extern int do_syscall_WRK (
890           int a1, int a2, int a3,
891           int a4, int a5, int a6, int syscall_no, UWord *err,
892           UWord *valHi, UWord* valLo
893        );
894 asm (
895    ".text                                  \n\t"
896    ".globl do_syscall_WRK                  \n\t"
897    ".type  do_syscall_WRK, @function       \n\t"
898    ".set push                              \n\t"
899    ".set noreorder                         \n\t"
900    "do_syscall_WRK:                        \n\t"
901    "   lw $2, 24($29)                      \n\t"
902    "   syscall                             \n\t"
903    "   lw $8, 28($29)                      \n\t"
904    "   sw $7, ($8)                         \n\t"
905    "   lw $8, 32($29)                      \n\t"
906    "   sw $3, ($8)                         \n\t" /* store valHi */
907    "   lw $8, 36($29)                      \n\t"
908    "   jr $31                              \n\t"
909    "   sw $2, ($8)                         \n\t" /* store valLo */
910    ".size do_syscall_WRK, .-do_syscall_WRK \n\t"
911    ".set pop                               \n\t"
912    ".previous                              \n\t"
913 );
914 
915 #elif defined(VGP_mips64_linux)
916 extern RegWord do_syscall_WRK ( RegWord a1, RegWord a2, RegWord a3, RegWord a4,
917                                 RegWord a5, RegWord a6, RegWord syscall_no,
918                                 RegWord* V1_A3_val );
919 asm (
920    ".text                                  \n\t"
921    ".globl do_syscall_WRK                  \n\t"
922    ".type  do_syscall_WRK, @function       \n\t"
923    ".set push                              \n\t"
924    ".set noreorder                         \n\t"
925    "do_syscall_WRK:                        \n\t"
926    "   daddiu $29, $29, -8                 \n\t"
927    "   sd $11, 0($29)                      \n\t"
928    "   move $2, $10                        \n\t"
929    "   syscall                             \n\t"
930    "   ld $11, 0($29)                      \n\t"
931    "   daddiu $29, $29, 8                  \n\t"
932    "   sd $3, 0($11)                       \n\t" /* store v1 in last param */
933    "   jr $31                              \n\t"
934    "   sd $7, 8($11)                       \n\t" /* store a3 in last param */
935    ".size do_syscall_WRK, .-do_syscall_WRK \n\t"
936    ".set pop                               \n\t"
937    ".previous                              \n\t"
938 );
939 
940 #elif defined(VGP_x86_solaris)
941 
942 extern ULong
943 do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* 4(esp)..12(esp) */
944                UWord a4, UWord a5, UWord a6,    /* 16(esp)..24(esp) */
945                UWord a7, UWord a8,              /* 28(esp)..32(esp) */
946                UWord syscall_no,                /* 36(esp) */
947                /*OUT*/UInt *errflag);           /* 40(esp) */
948 /* Classic unix syscall.. parameters on the stack, an unused (by the kernel)
949    return address at 0(esp), a sysno in eax, a result in edx:eax, the carry
950    flag set on error. */
951 __asm__ (
952 ".text\n"
953 ".globl do_syscall_WRK\n"
954 "do_syscall_WRK:\n"
955 "       movl    40(%esp), %ecx\n"       /* assume syscall success */
956 "       movl    $0, (%ecx)\n"
957 "       movl    36(%esp), %eax\n"
958 "       int     $0x91\n"
959 "       jnc     1f\n"                   /* jump if success */
960 "       movl    40(%esp), %ecx\n"       /* syscall failed - set *errflag */
961 "       movl    $1, (%ecx)\n"
962 "1:     ret\n"
963 ".previous\n"
964 );
965 
966 extern ULong
967 do_syscall_fast_WRK(UWord syscall_no);          /* 4(esp) */
968 /* Fasttrap syscall.. no parameters, a sysno in eax, a result in edx:eax,
969    never fails (if the sysno is valid). */
970 __asm__ (
971 ".text\n"
972 ".globl do_syscall_fast_WRK\n"
973 "do_syscall_fast_WRK:\n"
974 "       movl    4(%esp), %eax\n"
975 "       int     $0xD2\n"
976 "       ret\n"
977 ".previous\n"
978 );
979 
980 #elif defined(VGP_amd64_solaris)
981 
982 extern ULong
983 do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* rdi, rsi, rdx */
984                UWord a4, UWord a5, UWord a6,    /* rcx, r8, r9 */
985                UWord a7, UWord a8,              /* 8(rsp), 16(rsp) */
986                UWord syscall_no,                /* 24(rsp) */
987                /*OUT*/ULong *errflag,           /* 32(rsp) */
988                /*OUT*/ULong *res2);             /* 40(rsp) */
989 /* First 6 parameters in registers rdi, rsi, rdx, r10, r8, r9, next
990    2 parameters on the stack, an unused (by the kernel) return address at
991    0(rsp), a sysno in rax, a result in rdx:rax, the carry flag set on
992    error. */
993 __asm__ (
994 ".text\n"
995 ".globl do_syscall_WRK\n"
996 "do_syscall_WRK:\n"
997 "       movq    %rcx, %r10\n"           /* pass rcx in r10 instead */
998 "       movq    32(%rsp), %rcx\n"       /* assume syscall success */
999 "       movq    $0, (%rcx)\n"
1000 "       movq    24(%rsp), %rax\n"
1001 "       syscall\n"
1002 "       jnc     1f\n"                   /* jump if success */
1003 "       movq    32(%rsp), %rcx\n"       /* syscall failed - set *errflag */
1004 "       movq    $1, (%rcx)\n"
1005 "1:     movq    40(%rsp), %rcx\n"       /* save 2nd result word */
1006 "       movq    %rdx, (%rcx)\n"
1007 "       ret\n"
1008 ".previous\n"
1009 );
1010 
1011 extern ULong
1012 do_syscall_fast_WRK(UWord syscall_no,           /* rdi */
1013                     /*OUT*/ULong *res2);        /* rsi */
1014 /* Fasttrap syscall.. no parameters, a sysno in rax, a result in rdx:rax,
1015    never fails (if the sysno is valid). */
1016 __asm__ (
1017 ".text\n"
1018 ".globl do_syscall_fast_WRK\n"
1019 "do_syscall_fast_WRK:\n"
1020 "       movq    %rdi, %rax\n"
1021 "       int     $0xD2\n"
1022 "       movq    %rdx, (%rsi)\n"         /* save 2nd result word */
1023 "       ret\n"
1024 ".previous\n"
1025 );
1026 
1027 #else
1028 #  error Unknown platform
1029 #endif
1030 
1031 
1032 /* Finally, the generic code.  This sends the call to the right
1033    helper. */
1034 
VG_(do_syscall)1035 SysRes VG_(do_syscall) ( UWord sysno, RegWord a1, RegWord a2, RegWord a3,
1036                                       RegWord a4, RegWord a5, RegWord a6,
1037                                       RegWord a7, RegWord a8 )
1038 {
1039 #  if defined(VGP_x86_linux)
1040    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1041    return VG_(mk_SysRes_x86_linux)( val );
1042 
1043 #  elif defined(VGP_amd64_linux)
1044    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1045    return VG_(mk_SysRes_amd64_linux)( val );
1046 
1047 #  elif defined(VGP_x86_dragonfly)
1048    ULong val;
1049    UInt err = 0;
1050    val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5,
1051                         a6, a7, a8, &err);
1052    return VG_(mk_SysRes_x86_dragonfly)( (UInt)val, (UInt)(val>>32), (err & 1) != 0 ? True : False);
1053 
1054 #  elif defined(VGP_amd64_dragonfly)
1055    UWord val;
1056    UWord val2 = 0;
1057    UInt err = 0;
1058    if (sysno == __NR___sysctl) {
1059       val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5, a6, a7, a8, &err, &val2);
1060    }
1061    else {
1062       val = do_syscall_WRK(__NR___syscall, sysno, a1, a2, a3, a4, a5,
1063                         a6, a7, &err, &val2);
1064    }
1065    return VG_(mk_SysRes_amd64_dragonfly)( val, val2, (err & 1) != 0 ? True : False);
1066 
1067 #  elif defined(VGP_ppc32_linux)
1068    ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1069    UInt  val     = (UInt)(ret>>32);
1070    UInt  cr0so   = (UInt)(ret);
1071    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
1072 
1073 #  elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
1074    ULong argblock[7];
1075    argblock[0] = sysno;
1076    argblock[1] = a1;
1077    argblock[2] = a2;
1078    argblock[3] = a3;
1079    argblock[4] = a4;
1080    argblock[5] = a5;
1081    argblock[6] = a6;
1082    do_syscall_WRK( &argblock[0] );
1083    return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
1084 
1085 #  elif defined(VGP_arm_linux)
1086    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
1087    return VG_(mk_SysRes_arm_linux)( val );
1088 
1089 #  elif defined(VGP_arm64_linux)
1090    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
1091    return VG_(mk_SysRes_arm64_linux)( val );
1092 
1093 #  elif defined(VGP_x86_darwin)
1094    UInt  wLO = 0, wHI = 0, err = 0;
1095    ULong u64;
1096    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
1097    switch (scclass) {
1098       case VG_DARWIN_SYSCALL_CLASS_UNIX:
1099          u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1100                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
1101          wLO = (UInt)u64;
1102          wHI = (UInt)(u64 >> 32);
1103          break;
1104       case VG_DARWIN_SYSCALL_CLASS_MACH:
1105          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1106                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1107          err = 0;
1108          break;
1109       case VG_DARWIN_SYSCALL_CLASS_MDEP:
1110          wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1111                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1112          err = 0;
1113          break;
1114       default:
1115          vg_assert(0);
1116          break;
1117    }
1118    return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
1119 
1120 #  elif defined(VGP_amd64_darwin)
1121    ULong wLO = 0, wHI = 0, err = 0;
1122    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
1123    switch (scclass) {
1124       case VG_DARWIN_SYSCALL_CLASS_UNIX:
1125          wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1126                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
1127          break;
1128       case VG_DARWIN_SYSCALL_CLASS_MACH:
1129       case VG_DARWIN_SYSCALL_CLASS_MDEP:
1130          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1131                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1132          err = 0;
1133          break;
1134       default:
1135          vg_assert(0);
1136          break;
1137    }
1138    return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
1139 
1140 #elif defined(VGP_s390x_linux)
1141    UWord val;
1142 
1143    if (sysno == __NR_mmap) {
1144      ULong argbuf[6];
1145 
1146      argbuf[0] = a1;
1147      argbuf[1] = a2;
1148      argbuf[2] = a3;
1149      argbuf[3] = a4;
1150      argbuf[4] = a5;
1151      argbuf[5] = a6;
1152      val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
1153    } else {
1154      val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1155    }
1156 
1157    return VG_(mk_SysRes_s390x_linux)( val );
1158 
1159 #elif defined(VGP_mips32_linux)
1160    UWord err   = 0;
1161    UWord valHi = 0;
1162    UWord valLo = 0;
1163    (void) do_syscall_WRK(a1,a2,a3,a4,a5,a6, sysno,&err,&valHi,&valLo);
1164    return VG_(mk_SysRes_mips32_linux)( valLo, valHi, (ULong)err );
1165 
1166 #elif defined(VGP_mips64_linux)
1167    RegWord v1_a3[2];
1168    v1_a3[0] = 0xFF00;
1169    v1_a3[1] = 0xFF00;
1170    RegWord V0 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno,v1_a3);
1171    RegWord V1 = (RegWord)v1_a3[0];
1172    RegWord A3 = (RegWord)v1_a3[1];
1173    return VG_(mk_SysRes_mips64_linux)( V0, V1, A3 );
1174 
1175 #  elif defined(VGP_x86_solaris)
1176    UInt val, val2, err = False;
1177    Bool restart;
1178    ULong u64;
1179    UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
1180 
1181    switch (ssclass) {
1182       case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
1183          /* The Solaris kernel does not restart syscalls automatically so it
1184             is done here. */
1185          do {
1186             u64 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1187                                  VG_SOLARIS_SYSNO_INDEX(sysno), &err);
1188             val = (UInt)u64;
1189             restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
1190          } while (restart);
1191          break;
1192       case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
1193          u64 = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno));
1194          break;
1195       default:
1196          vg_assert(0);
1197          break;
1198    }
1199 
1200    val = (UInt)u64;
1201    val2 = (UInt)(u64 >> 32);
1202    return VG_(mk_SysRes_x86_solaris)(err ? True : False, val,
1203                                      err ? 0 : val2);
1204 
1205 #  elif defined(VGP_amd64_solaris)
1206    ULong val, val2, err = False;
1207    Bool restart;
1208    UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
1209 
1210    switch (ssclass) {
1211       case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
1212          /* The Solaris kernel does not restart syscalls automatically so it
1213             is done here. */
1214          do {
1215             val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1216                                  VG_SOLARIS_SYSNO_INDEX(sysno), &err, &val2);
1217             restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
1218          } while (restart);
1219          break;
1220       case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
1221          val = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno), &val2);
1222          break;
1223       default:
1224          vg_assert(0);
1225          break;
1226    }
1227 
1228    return VG_(mk_SysRes_amd64_solaris)(err ? True : False, val,
1229                                        err ? 0 : val2);
1230 
1231 #else
1232 #  error Unknown platform
1233 #endif
1234 }
1235 
1236 /* ---------------------------------------------------------------------
1237    Names of errors.
1238    ------------------------------------------------------------------ */
1239 
1240 /* Return a string which gives the name of an error value.  Note,
1241    unlike the standard C syserror fn, the returned string is not
1242    malloc-allocated or writable -- treat it as a constant.
1243    TODO: implement this properly. */
1244 
VG_(strerror)1245 const HChar* VG_(strerror) ( UWord errnum )
1246 {
1247    switch (errnum) {
1248    case VKI_EPERM:       return "Operation not permitted";
1249    case VKI_ENOENT:      return "No such file or directory";
1250    case VKI_ESRCH:       return "No such process";
1251    case VKI_EINTR:       return "Interrupted system call";
1252    case VKI_EIO:         return "Input/output error";
1253    case VKI_ENXIO:       return "No such device or address";
1254    case VKI_E2BIG:       return "Argument list too long";
1255    case VKI_ENOEXEC:     return "Exec format error";
1256    case VKI_EBADF:       return "Bad file descriptor";
1257    case VKI_ECHILD:      return "No child processes";
1258    case VKI_EAGAIN:      return "Resource temporarily unavailable";
1259    case VKI_ENOMEM:      return "Cannot allocate memory";
1260    case VKI_EACCES:      return "Permission denied";
1261    case VKI_EFAULT:      return "Bad address";
1262    case VKI_ENOTBLK:     return "Block device required";
1263    case VKI_EBUSY:       return "Device or resource busy";
1264    case VKI_EEXIST:      return "File exists";
1265    case VKI_EXDEV:       return "Invalid cross-device link";
1266    case VKI_ENODEV:      return "No such device";
1267    case VKI_ENOTDIR:     return "Not a directory";
1268    case VKI_EISDIR:      return "Is a directory";
1269    case VKI_EINVAL:      return "Invalid argument";
1270    case VKI_ENFILE:      return "Too many open files in system";
1271    case VKI_EMFILE:      return "Too many open files";
1272    case VKI_ENOTTY:      return "Inappropriate ioctl for device";
1273    case VKI_ETXTBSY:     return "Text file busy";
1274    case VKI_EFBIG:       return "File too large";
1275    case VKI_ENOSPC:      return "No space left on device";
1276    case VKI_ESPIPE:      return "Illegal seek";
1277    case VKI_EROFS:       return "Read-only file system";
1278    case VKI_EMLINK:      return "Too many links";
1279    case VKI_EPIPE:       return "Broken pipe";
1280    case VKI_EDOM:        return "Numerical argument out of domain";
1281    case VKI_ERANGE:      return "Numerical result out of range";
1282 
1283    case VKI_ENOSYS:      return "Function not implemented";
1284    case VKI_EOVERFLOW:   return "Value too large for defined data type";
1285 #     if defined(VKI_ERESTARTSYS)
1286       case VKI_ERESTARTSYS: return "ERESTARTSYS";
1287 #     endif
1288    default:              return "VG_(strerror): unknown error";
1289    }
1290 }
1291 
1292 
1293 /*--------------------------------------------------------------------*/
1294 /*--- end                                                          ---*/
1295 /*--------------------------------------------------------------------*/
1296