• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VG_(mk_SysRes_x86_linux)63 SysRes 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 .. */
VG_(mk_SysRes_amd64_linux)75 SysRes 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 */
VG_(mk_SysRes_ppc32_linux)88 SysRes 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 */
VG_(mk_SysRes_ppc64_linux)96 SysRes 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 
VG_(mk_SysRes_s390x_linux)103 SysRes 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 
VG_(mk_SysRes_arm_linux)114 SysRes 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. */
VG_(mk_SysRes_Error)126 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
127    SysRes r;
128    r._isError = True;
129    r._val     = err;
130    return r;
131 }
132 
VG_(mk_SysRes_Success)133 SysRes 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. */
VG_(mk_SysRes_x86_darwin)144 SysRes 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 
VG_(mk_SysRes_amd64_darwin)177 SysRes 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. */
VG_(mk_SysRes_Error)213 SysRes 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 
VG_(mk_SysRes_Success)221 SysRes 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 */
251 extern UWord do_syscall_WRK (
252           UWord syscall_no,
253           UWord a1, UWord a2, UWord a3,
254           UWord a4, UWord a5, UWord a6
255        );
256 asm(
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 */
292 extern UWord do_syscall_WRK (
293           UWord syscall_no,
294           UWord a1, UWord a2, UWord a3,
295           UWord a4, UWord a5, UWord a6
296        );
297 asm(
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 */
326 extern ULong do_syscall_WRK (
327           UWord syscall_no,
328           UWord a1, UWord a2, UWord a3,
329           UWord a4, UWord a5, UWord a6
330        );
331 asm(
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]. */
354 extern void do_syscall_WRK ( ULong* argblock );
355 asm(
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 */
392 extern UWord do_syscall_WRK (
393           UWord a1, UWord a2, UWord a3,
394           UWord a4, UWord a5, UWord a6,
395           UWord syscall_no
396        );
397 asm(
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
439 do_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
446 asm(".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
459 do_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
464 asm(".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
472 do_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
477 asm(
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
505 do_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
513 asm(".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
529 do_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
534 asm(".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 
do_syscall_WRK(UWord syscall_no,UWord arg1,UWord arg2,UWord arg3,UWord arg4,UWord arg5,UWord arg6)544 static 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 
VG_(do_syscall)582 SysRes 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 
VG_(strerror)695 const 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