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