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