]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syscall.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_syscall.c
1 // vim: expandtab
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-2010 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 #include "pub_core_tooliface.h"
37 #include "pub_tool_tooliface.h"
38
39 #if defined(VGO_l4re)
40 #include "pub_core_threadstate.h"
41 #include "coregrind/m_syswrap/priv_types_n_macros.h"
42 #include "pub_core_debuglog.h"
43 #include "pub_core_libcprint.h"
44 #include "pub_core_aspacemgr.h"
45 #include "pub_tool_options.h"
46 #include "pub_tool_libcbase.h"
47 #include "pub_tool_stacktrace.h"
48 #include <l4/sys/types.h>
49 #include <l4/sys/utcb.h>
50 #include <l4/sys/ipc.h>
51 #endif
52 /* ---------------------------------------------------------------------
53    Building syscall return values.
54    ------------------------------------------------------------------ */
55
56 #if defined(VGO_linux)
57
58 /* Make a SysRes value from a syscall return value.  This is
59    Linux-specific.
60
61    From:
62    http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/
63    linux/i386/sysdep.h?
64    rev=1.28&content-type=text/x-cvsweb-markup&cvsroot=glibc
65
66    Linux uses a negative return value to indicate syscall errors,
67    unlike most Unices, which use the condition codes' carry flag.
68
69    Since version 2.1 the return value of a system call might be
70    negative even if the call succeeded.  E.g., the 'lseek' system call
71    might return a large offset.  Therefore we must not anymore test
72    for < 0, but test for a real error by making sure the value in %eax
73    is a real error number.  Linus said he will make sure the no
74    syscall returns a value in -1 .. -4095 as a valid result so we can
75    safely test with -4095.
76 */
77
78 SysRes VG_(mk_SysRes_x86_linux) ( Int val ) {
79    SysRes res;
80    res._isError = val >= -4095 && val <= -1;
81    if (res._isError) {
82       res._val = (UInt)(-val);
83    } else {
84       res._val = (UInt)val;
85    }
86    return res;
87 }
88
89 /* Similarly .. */
90 SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
91    SysRes res;
92    res._isError = val >= -4095 && val <= -1;
93    if (res._isError) {
94       res._val = (ULong)(-val);
95    } else {
96       res._val = (ULong)val;
97    }
98    return res;
99 }
100
101 /* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speak) */
102 /* Note this must be in the bottom bit of the second arg */
103 SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
104    SysRes res;
105    res._isError = (cr0so & 1) != 0;
106    res._val     = val;
107    return res;
108 }
109
110 /* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
111 SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
112    SysRes res;
113    res._isError = (cr0so & 1) != 0;
114    res._val     = val;
115    return res;
116 }
117
118 SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
119    SysRes res;
120    res._isError = val >= -4095 && val <= -1;
121    if (res._isError) {
122       res._val = -val;
123    } else {
124       res._val = val;
125    }
126    return res;
127 }
128
129 SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
130    SysRes res;
131    res._isError = val >= -4095 && val <= -1;
132    if (res._isError) {
133       res._val = (UInt)(-val);
134    } else {
135       res._val = (UInt)val;
136    }
137    return res;
138 }
139
140 /* Generic constructors. */
141 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
142    SysRes r;
143    r._isError = True;
144    r._val     = err;
145    return r;
146 }
147
148 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
149    SysRes r;
150    r._isError = False;
151    r._val     = res;
152    return r;
153 }
154
155
156 #elif defined(VGO_aix5)
157
158 /* AIX scheme: we have to record both 'res' (r3) and 'err' (r4).  If
159    'err' is nonzero then the call has failed, but it could still be
160    that AIX userspace will ignore 'err' and instead consult 'res' to
161    determine if the call failed.  So we have to record both. */
162 SysRes VG_(mk_SysRes_ppc32_aix5) ( UInt res, UInt err ) {
163    SysRes r;
164    r.res     = res;
165    r.err     = err;
166    r.isError = r.err != 0;
167    return r;
168 }
169
170 SysRes VG_(mk_SysRes_ppc64_aix5) ( ULong res, ULong err ) {
171    SysRes r;
172    r.res     = res;
173    r.err     = err;
174    r.isError = r.err != 0;
175    return r;
176 }
177
178 /* Generic constructors. */
179 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
180    SysRes r;
181    r._res     = 0;
182    r._err     = err;
183    r._isError = True;
184    return r;
185 }
186
187 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
188    SysRes r;
189    r._res     = res;
190    r._err     = 0;
191    r._isError = False;
192    return r;
193 }
194
195
196 #elif defined(VGO_darwin)
197
198 /* Darwin: Some syscalls return a double-word result. */
199 SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
200                                    UInt wHI, UInt wLO )
201 {
202    SysRes res;
203    res._wHI  = 0;
204    res._wLO  = 0;
205    res._mode = 0; /* invalid */
206    vg_assert(isErr == False || isErr == True);
207    vg_assert(sizeof(UWord) == sizeof(UInt));
208    switch (scclass) {
209       case VG_DARWIN_SYSCALL_CLASS_UNIX:
210          res._wLO  = wLO;
211          res._wHI  = wHI;
212          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
213          break;
214       case VG_DARWIN_SYSCALL_CLASS_MACH:
215          vg_assert(!isErr);
216          vg_assert(wHI == 0);
217          res._wLO  = wLO;
218          res._mode = SysRes_MACH;
219          break;
220       case VG_DARWIN_SYSCALL_CLASS_MDEP:
221          vg_assert(!isErr);
222          vg_assert(wHI == 0);
223          res._wLO  = wLO;
224          res._mode = SysRes_MDEP;
225          break;
226       default:
227          vg_assert(0);
228    }
229    return res;
230 }
231
232 SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
233                                      ULong wHI, ULong wLO )
234 {
235    SysRes res;
236    res._wHI  = 0;
237    res._wLO  = 0;
238    res._mode = 0; /* invalid */
239    vg_assert(isErr == False || isErr == True);
240    vg_assert(sizeof(UWord) == sizeof(ULong));
241    switch (scclass) {
242       case VG_DARWIN_SYSCALL_CLASS_UNIX:
243          res._wLO  = wLO;
244          res._wHI  = wHI;
245          res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
246          break;
247       case VG_DARWIN_SYSCALL_CLASS_MACH:
248          vg_assert(!isErr);
249          vg_assert(wHI == 0);
250          res._wLO  = wLO;
251          res._mode = SysRes_MACH;
252          break;
253       case VG_DARWIN_SYSCALL_CLASS_MDEP:
254          vg_assert(!isErr);
255          vg_assert(wHI == 0);
256          res._wLO  = wLO;
257          res._mode = SysRes_MDEP;
258          break;
259       default:
260          vg_assert(0);
261    }
262    return res;
263 }
264
265 /* Generic constructors.  We assume (without checking if this makes
266    any sense, from the caller's point of view) that these are for the
267    UNIX style of syscall. */
268 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
269    SysRes r;
270    r._wHI  = 0;
271    r._wLO  = err;
272    r._mode = SysRes_UNIX_ERR;
273    return r;
274 }
275
276 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
277    SysRes r;
278    r._wHI  = 0;
279    r._wLO  = res;
280    r._mode = SysRes_UNIX_OK;
281    return r;
282 }
283
284 #elif defined(VGO_l4re)
285
286 SysRes VG_(mk_SysRes_x86_l4re) ( UInt val ) {
287    SysRes res;
288    res._isError = val >= -4095 && val <= -1;
289    if (res._isError) {
290       res._err = -val;
291       res._res = 0;
292    } else {
293       res._err = 0;
294       res._res = val;
295    }
296    return res;
297 }
298
299 /* Generic constructors. */
300 SysRes VG_(mk_SysRes_Error) ( UWord err ) {
301    SysRes r;
302    r._isError = True;
303    r._res     = err;
304    return r;
305 }
306
307 SysRes VG_(mk_SysRes_Success) ( UWord res ) {
308    SysRes r;
309    r._isError = False;
310    r._res     = res;
311    return r;
312 }
313
314 #else
315 #  error "Unknown OS"
316 #endif
317
318
319 /* ---------------------------------------------------------------------
320    VG_(do_syscall): A function for doing syscalls.
321    ------------------------------------------------------------------ */
322
323 #if defined(VGP_x86_linux)
324 /* Incoming args (syscall number + up to 6 args) come on the stack.
325    (ie. the C calling convention).
326
327    The syscall number goes in %eax.  The args are passed to the syscall in
328    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
329    calling convention.
330
331    %eax gets the return value.  Not sure which registers the kernel
332    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
333    %ebp).
334 */
335 extern UWord do_syscall_WRK (
336           UWord syscall_no, 
337           UWord a1, UWord a2, UWord a3,
338           UWord a4, UWord a5, UWord a6
339        );
340 asm(
341 ".text\n"
342 "do_syscall_WRK:\n"
343 "    push    %esi\n"
344 "    push    %edi\n"
345 "    push    %ebx\n"
346 "    push    %ebp\n"
347 "    movl    16+ 4(%esp),%eax\n"
348 "    movl    16+ 8(%esp),%ebx\n"
349 "    movl    16+12(%esp),%ecx\n"
350 "    movl    16+16(%esp),%edx\n"
351 "    movl    16+20(%esp),%esi\n"
352 "    movl    16+24(%esp),%edi\n"
353 "    movl    16+28(%esp),%ebp\n"
354 "    int    $0x80\n"
355 "    popl    %ebp\n"
356 "    popl    %ebx\n"
357 "    popl    %edi\n"
358 "    popl    %esi\n"
359 "    ret\n"
360 ".previous\n"
361 );
362
363 #elif defined(VGP_amd64_linux)
364 /* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
365    %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
366    calling convention).
367
368    The syscall number goes in %rax.  The args are passed to the syscall in
369    the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
370    ie. the kernel's syscall calling convention.
371
372    %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
373    no matter, they are caller-save (the syscall clobbers no callee-save
374    regs, so we don't have to do any register saving/restoring).
375 */
376 extern UWord do_syscall_WRK (
377           UWord syscall_no, 
378           UWord a1, UWord a2, UWord a3,
379           UWord a4, UWord a5, UWord a6
380        );
381 asm(
382 ".text\n"
383 "do_syscall_WRK:\n"
384         /* Convert function calling convention --> syscall calling
385            convention */
386 "    movq    %rdi, %rax\n"
387 "    movq    %rsi, %rdi\n"
388 "    movq    %rdx, %rsi\n"
389 "    movq    %rcx, %rdx\n"
390 "    movq    %r8,  %r10\n"
391 "    movq    %r9,  %r8\n"
392 "    movq    8(%rsp), %r9\n"     /* last arg from stack */
393 "    syscall\n"
394 "    ret\n"
395 ".previous\n"
396 );
397
398 #elif defined(VGP_ppc32_linux)
399 /* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
400
401    The syscall number goes in %r0.  The args are passed to the syscall in
402    the regs %r3:%r8, i.e. the kernel's syscall calling convention.
403
404    The %cr0.so bit flags an error.
405    We return the syscall return value in %r3, and the %cr0.so in 
406    the lowest bit of %r4.
407    We return a ULong, of which %r3 is the high word, and %r4 the low.
408    No callee-save regs are clobbered, so no saving/restoring is needed.
409 */
410 extern ULong do_syscall_WRK (
411           UWord syscall_no, 
412           UWord a1, UWord a2, UWord a3,
413           UWord a4, UWord a5, UWord a6
414        );
415 asm(
416 ".text\n"
417 "do_syscall_WRK:\n"
418 "        mr      0,3\n"
419 "        mr      3,4\n"
420 "        mr      4,5\n"
421 "        mr      5,6\n"
422 "        mr      6,7\n"
423 "        mr      7,8\n"
424 "        mr      8,9\n"
425 "        sc\n"                  /* syscall: sets %cr0.so on error         */
426 "        mfcr    4\n"           /* %cr -> low word of return var          */
427 "        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
428 "        blr\n"                 /* and return                             */
429 ".previous\n"
430 );
431
432 #elif defined(VGP_ppc64_linux)
433 /* Due to the need to return 65 bits of result, this is completely
434    different from the ppc32 case.  The single arg register points to a
435    7-word block containing the syscall # and the 6 args.  The syscall
436    result proper is put in [0] of the block, and %cr0.so is in the
437    bottom bit of [1]. */
438 extern void do_syscall_WRK ( ULong* argblock );
439 asm(
440 ".align   2\n"
441 ".globl   do_syscall_WRK\n"
442 ".section \".opd\",\"aw\"\n"
443 ".align   3\n"
444 "do_syscall_WRK:\n"
445 ".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
446 ".previous\n"
447 ".type    .do_syscall_WRK,@function\n"
448 ".globl   .do_syscall_WRK\n"
449 ".do_syscall_WRK:\n"
450 "        std  3,-16(1)\n"  /* stash arg */
451 "        ld   8, 48(3)\n"  /* sc arg 6 */
452 "        ld   7, 40(3)\n"  /* sc arg 5 */
453 "        ld   6, 32(3)\n"  /* sc arg 4 */
454 "        ld   5, 24(3)\n"  /* sc arg 3 */
455 "        ld   4, 16(3)\n"  /* sc arg 2 */
456 "        ld   0,  0(3)\n"  /* sc number */
457 "        ld   3,  8(3)\n"  /* sc arg 1 */
458 "        sc\n"             /* result in r3 and cr0.so */
459 "        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
460 "        std  3,0(5)\n"    /* argblock[0] = r3 */
461 "        mfcr 3\n"
462 "        srwi 3,3,28\n"
463 "        andi. 3,3,1\n"
464 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
465 "        blr\n"
466 );
467
468 #elif defined(VGP_arm_linux)
469 /* I think the conventions are:
470    args  in r0 r1 r2 r3 r4 r5
471    sysno in r7
472    return value in r0, w/ same conventions as x86-linux, viz r0 in
473    -4096 .. -1 is an error value.  All other values are success
474    values.
475 */
476 extern UWord do_syscall_WRK (
477           UWord a1, UWord a2, UWord a3,
478           UWord a4, UWord a5, UWord a6,
479           UWord syscall_no
480        );
481 asm(
482 ".text\n"
483 "do_syscall_WRK:\n"
484 "         push    {r4, r5, r7}\n"
485 "         ldr     r4, [sp, #12]\n"
486 "         ldr     r5, [sp, #16]\n"
487 "         ldr     r7, [sp, #20]\n"
488 "         svc     0x0\n"
489 "         pop     {r4, r5, r7}\n"
490 "         bx      lr\n"
491 ".previous\n"
492 );
493
494 #elif defined(VGP_ppc32_aix5)
495 static void do_syscall_WRK ( UWord* res_r3, UWord* res_r4,
496                              UWord sysno, 
497                              UWord a1, UWord a2, UWord a3,
498                              UWord a4, UWord a5, UWord a6,
499                              UWord a7, UWord a8 )
500 {
501    /* Syscalls on AIX are very similar to function calls:
502       - up to 8 args in r3-r10
503       - syscall number in r2
504       - kernel resumes at 'lr', so must set it appropriately beforehand
505       - r3 holds the result and r4 any applicable error code
506       See http://www.cs.utexas.edu/users/cart/publications/tr00-04.ps
507       and also 'man truss'.
508    */
509    /* For some reason gcc-3.3.2 doesn't preserve r31 across the asm
510       even though we state it to be trashed.  So use r27 instead. */
511    UWord args[9];
512    args[0] = sysno;
513    args[1] = a1; args[2] = a2;
514    args[3] = a3; args[4] = a4;
515    args[5] = a5; args[6] = a6;
516    args[7] = a7; args[8] = a8;
517
518    __asm__ __volatile__(
519
520       // establish base ptr
521       "mr   28,%0\n\t"
522
523       // save r2, lr
524       "mr   27,2\n\t" // save r2 in r27
525       "mflr 30\n\t"   // save lr in r30
526
527       // set syscall number and args
528       "lwz   2,  0(28)\n\t"
529       "lwz   3,  4(28)\n\t"
530       "lwz   4,  8(28)\n\t"
531       "lwz   5, 12(28)\n\t"
532       "lwz   6, 16(28)\n\t"
533       "lwz   7, 20(28)\n\t"
534       "lwz   8, 24(28)\n\t"
535       "lwz   9, 28(28)\n\t"
536       "lwz  10, 32(28)\n\t"
537
538       // set bit 3 of CR1 otherwise AIX 5.1 returns to the
539       // wrong address after the sc instruction
540       "crorc 6,6,6\n\t"
541
542       // set up LR to point just after the sc insn
543       ".long 0x48000005\n\t" // "bl here+4" -- lr := & next insn
544       "mflr 29\n\t"
545       "addi 29,29,16\n\t"
546       "mtlr 29\n\t"
547
548       // do it!
549       "sc\n\t"
550
551       // result is now in r3; save it in args[0]
552       "stw  3,0(28)\n\t"
553       // error code in r4; save it in args[1]
554       "stw  4,4(28)\n\t"
555
556       // restore
557       "mr   2,27\n\t"
558       "mtlr 30\n\t"
559
560       : /*out*/
561       : /*in*/  "b" (&args[0])
562       : /*trash*/
563            /*temps*/    "r31","r30","r29","r28","r27",
564            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
565            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
566                         "xer","ctr","cr0","cr1","cr2","cr3",
567                         "cr4","cr5","cr6","cr7"
568    );
569
570    *res_r3 = args[0];
571    *res_r4 = args[1];
572 }
573
574 #elif defined(VGP_ppc64_aix5)
575 static void do_syscall_WRK ( UWord* res_r3, UWord* res_r4,
576                              UWord sysno, 
577                              UWord a1, UWord a2, UWord a3,
578                              UWord a4, UWord a5, UWord a6,
579                              UWord a7, UWord a8 )
580 {
581    /* Same scheme as ppc32-aix5. */
582    UWord args[9];
583    args[0] = sysno;
584    args[1] = a1; args[2] = a2;
585    args[3] = a3; args[4] = a4;
586    args[5] = a5; args[6] = a6;
587    args[7] = a7; args[8] = a8;
588
589    __asm__ __volatile__(
590
591       // establish base ptr
592       "mr   28,%0\n\t"
593
594       // save r2, lr
595       "mr   27,2\n\t" // save r2 in r27
596       "mflr 30\n\t"   // save lr in r30
597
598       // set syscall number and args
599       "ld    2,  0(28)\n\t"
600       "ld    3,  8(28)\n\t"
601       "ld    4, 16(28)\n\t"
602       "ld    5, 24(28)\n\t"
603       "ld    6, 32(28)\n\t"
604       "ld    7, 40(28)\n\t"
605       "ld    8, 48(28)\n\t"
606       "ld    9, 56(28)\n\t"
607       "ld   10, 64(28)\n\t"
608
609       // set bit 3 of CR1 otherwise AIX 5.1 returns to the
610       // wrong address after the sc instruction
611       "crorc 6,6,6\n\t"
612
613       // set up LR to point just after the sc insn
614       ".long 0x48000005\n\t" // "bl here+4" -- lr := & next insn
615       "mflr 29\n\t"
616       "addi 29,29,16\n\t"
617       "mtlr 29\n\t"
618
619       // do it!
620       "sc\n\t"
621
622       // result is now in r3; save it in args[0]
623       "std  3,0(28)\n\t"
624       // error code in r4; save it in args[1]
625       "std  4,8(28)\n\t"
626
627       // restore
628       "mr   2,27\n\t"
629       "mtlr 30\n\t"
630
631       : /*out*/
632       : /*in*/  "b" (&args[0])
633       : /*trash*/
634            /*temps*/    "r31","r30","r29","r28","r27",
635            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
636            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
637                         "xer","ctr","cr0","cr1","cr2","cr3",
638                         "cr4","cr5","cr6","cr7"
639    );
640
641    *res_r3 = args[0];
642    *res_r4 = args[1];
643 }
644
645 #elif defined(VGP_x86_darwin)
646
647 /* Incoming args (syscall number + up to 8 args) come in on the stack
648
649    The kernel's syscall calling convention is:
650    * the syscall number goes in eax
651    * the args are passed to the syscall on the stack,
652      pushed onto the stack R->L (that is, the usual x86
653      calling conventions, with the leftmost arg at the lowest
654      address)
655    Call instruction:
656    * UNIX: sysenter
657    * UNIX: int $0x80
658    * MACH: int $0x81
659    * MDEP: int $0x82
660    Note that the call type can be determined from the syscall number;
661    there is no need to inspect the actual instruction.  Although obviously
662    the instruction must match.
663    Return value:
664    * MACH,MDEP: the return value comes back in eax
665    * UNIX: the return value comes back in edx:eax (hi32:lo32)
666    Error:
667    * MACH,MDEP: no error is returned
668    * UNIX: the carry flag indicates success or failure
669
670    nb here, sizeof(UWord) == sizeof(UInt)
671 */
672
673 __private_extern__ ULong 
674 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
675                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
676                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
677                       UWord syscall_no, /* 36(esp) */
678                       /*OUT*/UInt* errflag /* 40(esp) */ );
679 // Unix syscall: 64-bit return in edx:eax, with LSB in eax
680 // error indicated by carry flag: clear=good, set=bad
681 asm(".private_extern _do_syscall_unix_WRK\n"
682     "_do_syscall_unix_WRK:\n"
683     "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
684     "        movl    $0, (%ecx)       \n"
685     "        movl    36(%esp), %eax   \n"
686     "        int     $0x80            \n"
687     "        jnc     1f               \n"  /* jump if success */
688     "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
689     "        movl    $1, (%ecx)       \n"
690     "    1:  ret                      \n"
691     );
692
693 __private_extern__ UInt 
694 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
695                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
696                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
697                       UWord syscall_no /* 36(esp) */ );
698 // Mach trap: 32-bit result in %eax, no error flag
699 asm(".private_extern _do_syscall_mach_WRK\n"
700     "_do_syscall_mach_WRK:\n"
701     "        movl    36(%esp), %eax   \n"
702     "        int     $0x81            \n"
703     "        ret                      \n"
704     );
705
706 __private_extern__ UInt 
707 do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
708                       UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
709                       UWord a7, UWord a8, /* 28(esp)..32(esp) */
710                       UWord syscall_no /* 36(esp) */ );
711 // mdep trap: 32-bit result in %eax, no error flag
712 asm(
713     ".private_extern _do_syscall_mdep_WRK\n"
714     "_do_syscall_mdep_WRK:\n"
715     "        movl    36(%esp), %eax   \n"
716     "        int     $0x82            \n"
717     "        ret                      \n"
718     );
719
720
721 #elif defined(VGP_amd64_darwin)
722
723 /* Incoming args (syscall number + up to 8 args) come in registers and stack
724
725    The kernel's syscall calling convention is:
726    * the syscall number goes in rax
727    * the args are passed to the syscall in registers and the stack
728    * the call instruction is 'syscall'
729    Return value:
730    * MACH,MDEP: the return value comes back in rax
731    * UNIX: the return value comes back in rdx:rax (hi64:lo64)
732    Error:
733    * MACH,MDEP: no error is returned
734    * UNIX: the carry flag indicates success or failure
735
736    nb here, sizeof(UWord) == sizeof(ULong)
737 */
738
739 __private_extern__ UWord 
740 do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
741                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
742                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
743                       UWord syscall_no,             /* 24(rsp) */
744                       /*OUT*/ULong* errflag,        /* 32(rsp) */
745                       /*OUT*/ULong* res2 );         /* 40(rsp) */
746 // Unix syscall: 128-bit return in rax:rdx, with LSB in rax
747 // error indicated by carry flag: clear=good, set=bad
748 asm(".private_extern _do_syscall_unix_WRK\n"
749     "_do_syscall_unix_WRK:\n"
750     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
751     "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
752     "        movq    $0, (%rax)       \n"
753     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
754     "        syscall                  \n"
755     "        jnc     1f               \n"  /* jump if success */
756     "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
757     "        movq    $1, (%rcx)       \n"
758     "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
759     "        movq    %rdx, (%rcx)     \n"
760     "        retq                     \n"  /* return 1st result word */
761     );
762
763 __private_extern__ UWord 
764 do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
765                       UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
766                       UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
767                       UWord syscall_no );           /* 24(rsp) */
768 // Mach trap: 64-bit result, no error flag
769 asm(".private_extern _do_syscall_mach_WRK\n"
770     "_do_syscall_mach_WRK:\n"
771     "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
772     "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
773     "        syscall                  \n"
774     "        retq                     \n"
775     );
776
777 #elif defined(VGP_x86_l4re)
778 /* Incoming args (syscall number + up to 6 args) come on the stack.
779    (ie. the C calling convention).
780
781    The syscall number goes in %eax.  The args are passed to the syscall in
782    the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
783    calling convention.
784
785    %eax gets the return value.  Not sure which registers the kernel
786    clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
787    %ebp).
788 */
789
790 UWord do_l4re_syscall_WRK( SyscallArgs* args )
791 {
792    struct { unsigned d,v; } v = {args->arg5, args->arg6};
793
794    __asm__ __volatile__ (
795          "      push  %%ebp         \n\t"
796          "      movl  %[arg6], %%ebp  \n\t"
797          "      movl  4(%%esi), %%edi \n\t"
798          "      movl  (%%esi), %%esi  \n\t"
799 //         "      int   $0x3            \n\t"
800          "      int   $0x30           \n\t"
801          "      popl  %%ebp           \n\t"
802    :
803          "=a" (args->arg1), // eax
804          "=b" (args->arg2), // ebx
805          "=c" (args->arg3), // ecx
806          "=d" (args->arg4), // edx
807          "=S" (args->arg5), // esi
808          "=D" (args->arg6) // edi
809    :
810          "a" (args->arg1),
811          "b" (args->arg2),
812          "c" (args->arg3),
813          "d" (args->arg4),
814          "S" (&v),
815          [arg6] "m"((int)args->arg7)
816    :
817          "memory", "cc"
818       );
819
820    return 1;
821 }
822
823 UWord do_l4re_syscall_debug_WRK( SyscallArgs* args )
824 {
825    struct { unsigned d,v; } v = {args->arg5, args->arg6};
826
827    __asm__ __volatile__ (
828          "      int   $0x32           \n\t"
829    :
830          "=a" (args->arg1), // eax
831          "=d" (args->arg4), // edx
832          "=S" (args->arg5), // esi
833          "=D" (args->arg6)  // edi
834    :
835          "a" (args->arg1),
836          "d" (args->arg4),
837          "D" (args->arg6)
838    :
839          "memory", "cc"
840       );
841
842    return 1;
843 }
844
845
846 UWord handle_int80(SyscallArgs *args)
847 {
848    struct { unsigned d,v; } v = {args->arg5, args->arg6};
849     __asm__ __volatile__ (
850          "      push  %%ebp         \n\t"
851          "      movl  %[arg6], %%ebp  \n\t"
852          "      movl  4(%%esi), %%edi \n\t"
853          "      movl  (%%esi), %%esi  \n\t"
854          "      int   $0x80           \n\t"
855          "      popl  %%ebp           \n\t"
856    :
857          "=a" (args->arg1), // eax
858          "=b" (args->arg2), // ebx
859          "=c" (args->arg3), // ecx
860          "=d" (args->arg4), // edx
861          "=S" (args->arg5), // esi
862          "=D" (args->arg6) // edi
863    :
864          "a" (args->arg1),
865          "b" (args->arg2),
866          "c" (args->arg3),
867          "d" (args->arg4),
868          "S" (&v),
869          [arg6] "m"((int)args->arg7)
870    :
871          "memory", "cc"
872     );
873     return 1;
874 }
875
876
877 UWord do_l4re_syscall_enter_kdebug_WRK( SyscallArgs* args )
878 {
879    struct { unsigned d,v; } v = {args->arg5, args->arg6};
880    __asm__ __volatile__ (
881          "      int   $0x3            \n\t"
882    : : : "memory"
883       );
884    return 1;
885 }
886
887
888 UWord handle_ud2(SyscallArgs *a)
889 {
890     __asm__ __volatile__ (
891         "ud2\n\t"
892     );
893 }
894
895 #elif defined(VGP_s390x_linux)
896
897 static UWord do_syscall_WRK (
898    UWord syscall_no,
899    UWord arg1, UWord arg2, UWord arg3,
900    UWord arg4, UWord arg5, UWord arg6
901    )
902 {
903    register UWord __arg1 asm("2") = arg1;
904    register UWord __arg2 asm("3") = arg2;
905    register UWord __arg3 asm("4") = arg3;
906    register UWord __arg4 asm("5") = arg4;
907    register UWord __arg5 asm("6") = arg5;
908    register UWord __arg6 asm("7") = arg6;
909    register ULong __svcres asm("2");
910
911    __asm__ __volatile__ (
912                  "lgr %%r1,%1\n\t"
913                  "svc 0\n\t"
914                 : "=d" (__svcres)
915                 : "a" (syscall_no),
916                   "0" (__arg1),
917                   "d" (__arg2),
918                   "d" (__arg3),
919                   "d" (__arg4),
920                   "d" (__arg5),
921                   "d" (__arg6)
922                 : "1", "cc", "memory");
923
924    return (UWord) (__svcres);
925 }
926
927 #else
928 #  error Unknown platform
929 #endif
930
931
932 #if defined(VGO_l4re)
933 static void dump_args(char *str, SyscallArgs *args, l4_utcb_t *u, ThreadId tid)
934 {
935 //      l4_msg_regs_t *v = l4_utcb_mr_u(l4_utcb_wrap());
936 //      l4_msg_regs_t *v = l4_utcb_mr_u(VG_(threads)[VG_(get_running_tid)()].utcb);
937
938       l4_msg_regs_t *v = l4_utcb_mr_u(u);
939
940       VG_(debugLog)(0, "syscall", "%s\n", str);
941       VG_(debugLog)(0, "syscall", "Registers:\n"
942                                   "\t\t sysno = %08lx\n" 
943                                   "\t\t    a1 = EAX = 0x%08x  a1 = EBX = 0x%08x\n"
944                                   "\t\t    a2 = ECX = 0x%08x  a3 = EDX = 0x%08x\n"
945                                   "\t\t    a4 = ESI = 0x%08x  a5 = EDI = 0x%08x\n"
946                                   "\t\t    a6 = EBP = 0x%08x\n",
947                                   (int)args->sysno, (int)args->arg1,
948                                   (int)args->arg2,  (int)args->arg3,
949                                   (int)args->arg4,  (int)args->arg5,
950                                   (int)args->arg6,  (int)args->arg7);
951
952
953       VG_(debugLog)(0, "syscall", "UTCB contents:\n"
954                                   "\t\t         MR0 = 0x%08x MR1 = 0x%08x\n"
955                                   "\t\t         MR2 = 0x%08x MR2 = 0x%08x\n"
956                                   "\t\t         MR4 = 0x%08x MR4 = 0x%08x\n"
957                                   "\t\t         MR6 = 0x%08x MR6 = 0x%08x\n"
958                                   "\t\t         MR8 = 0x%08x MR8 = 0x%08x\n",
959                                   (unsigned int) v->mr[0], (unsigned int) v->mr[1],
960                                   (unsigned int) v->mr[2], (unsigned int) v->mr[3],
961                                   (unsigned int) v->mr[4], (unsigned int) v->mr[5],
962                                   (unsigned int) v->mr[6], (unsigned int) v->mr[7],
963                                   (unsigned int) v->mr[8], (unsigned int) v->mr[9]);
964 }
965
966 static void dump_backtrace(char *str, ThreadId tid)
967 {
968       VG_(debugLog)(0, "syscall", "Backtrace of client:\n", str);
969       VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
970 }
971
972
973 /* Handling for enter_kdebug(text)                 done
974  *              outchar(char)                      done
975  *              outstring(const char *)            done
976  *              outnstring(const char *, unsigned) done
977  *              outhex32(int)                      todo
978  *              outhex20(int)                      todo
979  *              outhex16(int)                      todo
980  *              outhex12(int)                      todo
981  *              outhex8(int)                       todo
982  *              outdec(int)                        todo
983  */
984
985 void handle_kdebug(SyscallArgs *args, ThreadId tid) {
986 #define MAX_STR_LEN 128
987 #define DEBUG_MYSELF 0
988     char str[MAX_STR_LEN];
989     Int len = -1;
990
991     char const *s1 = "\033[35m"; // color magenta
992     char const *s2 = "\033[0m";  // color reset
993
994     unsigned char *ip;
995     ip = VG_(threads)[tid].arch.vex.guest_EIP;
996 #if DEBUG_MYSELF
997     //VG_(debugLog)(0, "syscall", "%02X %02X %02X %02X\n", *ip, *(ip+1), *(ip+2), *(ip+3));
998     l4re_hexdump(ip, 16);
999 #endif 
1000     str[0] = 0;
1001     if (*(ip) == 0xEB /* jmp */) {
1002         /* enter_kdebug(text) */
1003         Int len = *(ip+1);
1004         vg_assert(len >= 0 && len < MAX_STR_LEN);
1005
1006         VG_(strncpy)(&str, ip + 2, len);
1007         str[len] = 0;
1008
1009         VG_(printf)("%senter_kdebug via client: %s%s\n", s1,  str, s2);
1010         VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
1011         do_l4re_syscall_enter_kdebug_WRK(args);
1012     } else if (*(ip) == 0x3C /* cmp */) {
1013         switch(*(ip + 1)) {
1014             case 0x0: /* outchar(char) */
1015                 {
1016                     Char c = VG_(threads)[tid].arch.vex.guest_EAX & 0x000000ff;
1017                     VG_(printf)("%s%c%s", s1, c , s2);
1018                     break;
1019                 }
1020             case 0x1: /* outnstring(const char*, unsigned) */
1021                 {
1022                     char *_str = VG_(threads)[tid].arch.vex.guest_EAX;
1023                     unsigned len = VG_(threads)[tid].arch.vex.guest_ECX;
1024                     vg_assert(len >= 0 && len < MAX_STR_LEN);
1025                     VG_(strncpy)(&str, _str, len);
1026                     str[len] = 0;
1027                     VG_(printf)("%s%s%s", s1, str , s2);
1028                     break;
1029                 }
1030             case 0x2: /* outstring(const char*) */
1031                 {
1032                     char *_str = VG_(threads)[tid].arch.vex.guest_EAX;
1033                     VG_(printf)("%s%s%s", s1, _str , s2);
1034                     break;
1035                 }
1036             case 0x5: /* outhex32(int) */
1037                 {
1038                     int n = VG_(threads)[tid].arch.vex.guest_EAX;
1039                     VG_(printf)("%s%x%s", s1, n, s2);
1040                     break;
1041                 }
1042             case 0xB /* 11 */: /* outdec(int) */
1043                 {
1044                     int n = VG_(threads)[tid].arch.vex.guest_EAX;
1045                     VG_(printf)("%s%d%s", s1, n, s2);
1046                     break;
1047                 }
1048
1049
1050             default:
1051                 {
1052                     VG_(printf)("%sunknown outXY()%s\n", s1, s2);
1053                     VG_(debugLog)(0, "syscall", "%x %x %x %x\n", *ip, *(ip+1), *(ip+2), *(ip+3));
1054                     do_l4re_syscall_enter_kdebug_WRK(args);
1055                 }
1056         }
1057     } else { /* everything else */
1058         VG_(printf)("%senter_kdebug via client%s\n", s1, s2);
1059         do_l4re_syscall_enter_kdebug_WRK(args);
1060     }
1061
1062 #undef DEBUG_MYSELF
1063 #undef MAX_STR_LEN
1064 }
1065
1066 Bool dbg_artificial_handling = DEBUG_OFF;
1067
1068 void handle_artificial(SyscallArgs *args)
1069 {
1070     L4RedirState *s = (L4RedirState *)args->arg1;
1071     switch(s->redir_type) {
1072         case LIBC_OPEN:
1073             if (dbg_artificial_handling) VG_(debugLog)(4, "systrp", "open(file='%s' flags=%08lx) = %d\n",
1074                                                s->open.path, s->open.flags, s->retval);
1075             vrm_register_filename(s->retval, s->open.path);
1076             break;
1077         case LIBC_CLOSE:
1078             if (dbg_artificial_handling) VG_(debugLog)(4, "systrp", "close(fd=%d) = %d\n",
1079                                                s->close.fd, s->retval);
1080             vrm_unregister_filename(s->close.fd);
1081             break;
1082         case LIBC_MMAP:
1083             {
1084                 if (dbg_artificial_handling) {
1085                     VG_(debugLog)(4, "systrp", "mmap(a=%08lx, size = %lx, prot = %08lx\n",
1086                                   s->mmap.addr, s->mmap.size, s->mmap.prot);
1087                     VG_(debugLog)(4, "systrp", "     fd = %d offset = %lx) = %lx\n",
1088                                   s->mmap.fd, s->mmap.offset, s->retval);
1089                 }
1090
1091                 /* Modify segment -> SkFileC */
1092                 if (s->mmap.fd >= 0) {
1093                     extern Int allocate_segname(const HChar *);
1094
1095                     HChar buf[VKI_PATH_MAX];
1096
1097                     /*
1098                      * The segment has already been registered (as anon client)
1099                      * by VRM. Now find it and adapt its type.
1100                      */
1101                     NSegment *seg = VG_(am_find_nsegment)(s->retval);
1102                     seg->kind = SkFileC;
1103
1104                     /*
1105                      * Also, store file offset and adapt the mapping's
1106                      * access rights properly.
1107                      */
1108                     seg->offset = s->mmap.offset;
1109                     seg->hasR   = toBool(s->mmap.prot & VKI_PROT_READ);
1110                     seg->hasW   = toBool(s->mmap.prot & VKI_PROT_WRITE);
1111                     seg->hasX   = toBool(s->mmap.prot & VKI_PROT_EXEC);
1112
1113                     VG_(strncpy)(buf, vrm_get_filename(s->mmap.fd), VKI_PATH_MAX);
1114                     seg->fnIdx = allocate_segname(buf);
1115
1116                     /*
1117                      * Finally, tell the debug info reader to check if
1118                      * it needs information from this.
1119                      */
1120                     VG_(di_notify_mmap)(s->mmap.addr, s->mmap.size);
1121                 }
1122             }
1123             break;
1124         default:
1125             VG_(printf)("Unknown artificial redir type: %lx\n", s->redir_type);
1126             enter_kdebug("unknown artificial redir\n");
1127             break;
1128     }
1129 }
1130
1131
1132 SysRes VG_(do_l4re_syscall) ( SyscallArgs *args, ThreadId tid )
1133 {
1134 #define DEBUG_MYSELF 0
1135     l4_utcb_t *utcb = l4_utcb_wrap();
1136
1137     // we havn't the big look - so malloc is a bad idea!!
1138     //void *vg_utcb = VG_(malloc)("vg_utcb", 512);
1139     char _vg_utcb[L4RE_UTCB_SIZE];
1140     void *vg_utcb = &_vg_utcb[0];
1141
1142 #if DEBUG_MYSELF
1143     VG_(debugLog)(0, "syscall", "\033[36mThe client makes a syscall tid = %d\033[0m\n"
1144             "\t\t real-utcb @ %p virt-utcb @ %p\n",
1145             tid,
1146             (void *)utcb,
1147             ts_utcb(&VG_(threads)[tid]));
1148
1149     dump_args("  -- Before syscall --", args, ts_utcb(&VG_(threads)[tid]), tid);
1150     dump_backtrace(" -- Before syscall --", tid);
1151 #endif
1152     // backup valgrinds utcb
1153     VG_(memcpy)(vg_utcb, utcb, L4RE_UTCB_SIZE);
1154
1155
1156     // virt utcb --> real utcb
1157     VG_(memcpy)(utcb, ts_utcb(&VG_(threads)[tid]), L4RE_UTCB_SIZE);
1158
1159     // do syscall for guest
1160     switch (args->sysno) {
1161         case SYS_INVOKE:
1162             do_l4re_syscall_WRK(args);
1163             break;
1164         case SYS_DEBUG:
1165             do_l4re_syscall_debug_WRK(args);
1166             break;
1167         case SYS_ENTER_KDEBUG:
1168             handle_kdebug(args, tid);
1169             break;
1170         case SYS_LINUX_INT80:
1171             handle_int80(args);
1172             break;
1173         case SYS_ARTIFICIAL:
1174             handle_artificial(args);
1175             break;
1176         case SYS_UD2:
1177             handle_ud2(args);
1178             break;
1179         default:
1180             VG_(printf)("unknown syscall: %lx\n", args->sysno);
1181             break;
1182     }
1183
1184     // real utcb --> virt utcb
1185     VG_(memcpy)(ts_utcb(&VG_(threads)[tid]), utcb, L4RE_UTCB_SIZE);
1186
1187     // restore valgrinds utcb
1188     VG_(memcpy)(utcb, vg_utcb, L4RE_UTCB_SIZE);
1189
1190
1191 #if DEBUG_MYSELF
1192     dump_args("  -- After syscall --", args, ts_utcb(&VG_(threads)[tid]), tid);
1193 #endif
1194
1195     return VG_(mk_SysRes_Success)(0);
1196 #undef DEBUG_MYSELF
1197 }
1198
1199 #endif
1200 /* Finally, the generic code.  This sends the call to the right
1201    helper. */
1202
1203 SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
1204                                       UWord a4, UWord a5, UWord a6,
1205                                       UWord a7, UWord a8 )
1206 {
1207 #  if defined(VGP_x86_linux)
1208    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1209    return VG_(mk_SysRes_x86_linux)( val );
1210
1211 #  elif defined(VGP_amd64_linux)
1212    UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1213    return VG_(mk_SysRes_amd64_linux)( val );
1214
1215 #  elif defined(VGP_ppc32_linux)
1216    ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1217    UInt  val     = (UInt)(ret>>32);
1218    UInt  cr0so   = (UInt)(ret);
1219    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
1220
1221 #  elif defined(VGP_ppc64_linux)
1222    ULong argblock[7];
1223    argblock[0] = sysno;
1224    argblock[1] = a1;
1225    argblock[2] = a2;
1226    argblock[3] = a3;
1227    argblock[4] = a4;
1228    argblock[5] = a5;
1229    argblock[6] = a6;
1230    do_syscall_WRK( &argblock[0] );
1231    return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
1232
1233 #  elif defined(VGP_arm_linux)
1234    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
1235    return VG_(mk_SysRes_arm_linux)( val );
1236
1237 #  elif defined(VGP_ppc32_aix5)
1238    UWord res;
1239    UWord err;
1240    do_syscall_WRK( &res, &err, 
1241            sysno, a1, a2, a3, a4, a5, a6, a7, a8);
1242    /* Try to set the error number to zero if the syscall hasn't
1243       really failed. */
1244    if (sysno == __NR_AIX5_kread
1245        || sysno == __NR_AIX5_kwrite) {
1246       if (res != (UWord)-1L)
1247          err = 0;
1248    }
1249    else if (sysno == __NR_AIX5_sigprocmask
1250             || sysno == __NR_AIX5__sigpending) {
1251       if (res == 0)
1252          err = 0;
1253    }
1254    return VG_(mk_SysRes_ppc32_aix5)( res, err );
1255
1256 #  elif defined(VGP_ppc64_aix5)
1257    UWord res;
1258    UWord err;
1259    do_syscall_WRK( &res, &err,
1260            sysno, a1, a2, a3, a4, a5, a6, a7, a8);
1261    /* Try to set the error number to zero if the syscall hasn't
1262       really failed. */
1263    if (sysno == __NR_AIX5_kread
1264        || sysno == __NR_AIX5_kwrite) {
1265       if (res != (UWord)-1L)
1266          err = 0;
1267    }
1268    else if (sysno == __NR_AIX5_sigprocmask
1269             || sysno == __NR_AIX5__sigpending) {
1270       if (res == 0)
1271          err = 0;
1272    }
1273    return VG_(mk_SysRes_ppc64_aix5)( res, err );
1274
1275 #  elif defined(VGP_x86_darwin)
1276    UInt  wLO = 0, wHI = 0, err = 0;
1277    ULong u64;
1278    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
1279    switch (scclass) {
1280       case VG_DARWIN_SYSCALL_CLASS_UNIX:
1281          u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1282                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
1283          wLO = (UInt)u64;
1284          wHI = (UInt)(u64 >> 32);
1285          break;
1286       case VG_DARWIN_SYSCALL_CLASS_MACH:
1287          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
1288                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1289          err = 0;
1290          break;
1291       case VG_DARWIN_SYSCALL_CLASS_MDEP:
1292          wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
1293                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1294          err = 0;
1295          break;
1296       default:
1297          vg_assert(0);
1298          break;
1299    }
1300    return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
1301
1302 #  elif defined(VGP_amd64_darwin)
1303    ULong wLO = 0, wHI = 0, err = 0;
1304    UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
1305    switch (scclass) {
1306       case VG_DARWIN_SYSCALL_CLASS_UNIX:
1307          wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
1308                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
1309          break;
1310       case VG_DARWIN_SYSCALL_CLASS_MACH:
1311       case VG_DARWIN_SYSCALL_CLASS_MDEP:
1312          wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
1313                                    VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
1314          err = 0;
1315          break;
1316       default:
1317          vg_assert(0);
1318          break;
1319    }
1320    return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
1321
1322 #elif defined(VGP_s390x_linux)
1323    UWord val;
1324
1325    if (sysno == __NR_mmap) {
1326      ULong argbuf[6];
1327
1328      argbuf[0] = a1;
1329      argbuf[1] = a2;
1330      argbuf[2] = a3;
1331      argbuf[3] = a4;
1332      argbuf[4] = a5;
1333      argbuf[5] = a6;
1334      val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
1335    } else {
1336      val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
1337    }
1338
1339    return VG_(mk_SysRes_s390x_linux)( val );
1340
1341 #elif defined(VGO_l4re)
1342    VG_(unimplemented)("unimplemented function VG_(do_syscall)");
1343    return VG_(mk_SysRes_Error)(1);
1344 #else
1345 #  error Unknown platform
1346 #endif
1347 }
1348
1349 /* ---------------------------------------------------------------------
1350    Names of errors.
1351    ------------------------------------------------------------------ */
1352
1353 /* Return a string which gives the name of an error value.  Note,
1354    unlike the standard C syserror fn, the returned string is not
1355    malloc-allocated or writable -- treat it as a constant. 
1356    TODO: implement this properly. */
1357
1358 const HChar* VG_(strerror) ( UWord errnum )
1359 {
1360    switch (errnum) {
1361       case VKI_EPERM:       return "Operation not permitted";
1362       case VKI_ENOENT:      return "No such file or directory";
1363       case VKI_ESRCH:       return "No such process";
1364       case VKI_EINTR:       return "Interrupted system call";
1365       case VKI_EBADF:       return "Bad file number";
1366       case VKI_EAGAIN:      return "Try again";
1367       case VKI_ENOMEM:      return "Out of memory";
1368       case VKI_EACCES:      return "Permission denied";
1369       case VKI_EFAULT:      return "Bad address";
1370       case VKI_EEXIST:      return "File exists";
1371       case VKI_EINVAL:      return "Invalid argument";
1372       case VKI_EMFILE:      return "Too many open files";
1373       case VKI_ENOSYS:      return "Function not implemented";
1374       case VKI_EOVERFLOW:   return "Value too large for defined data type";
1375 #     if defined(VKI_ERESTARTSYS)
1376       case VKI_ERESTARTSYS: return "ERESTARTSYS";
1377 #     endif
1378       default:
1379 #if defined(VGO_l4re)
1380                             VG_(debugLog)(1, "syscall", "%s: unknown errnum: %d\n", __func__, (int) errnum);
1381 #endif
1382                             return "VG_(strerror): unknown error";
1383    }
1384 }
1385
1386
1387 /*--------------------------------------------------------------------*/
1388 /*--- end                                                        ---*/
1389 /*--------------------------------------------------------------------*/