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