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