blob: 0810b5455d1d80aa8ce6df73fd96ea43bb207de9 [file] [log] [blame]
/*--- Support for doing system calls. syscall-amd64-linux.S ---*/
This file is part of Valgrind, a dynamic binary instrumentation
Copyright (C) 2000-2013 Julian Seward
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
#if defined(VGP_amd64_linux)
#include "pub_core_basics_asm.h"
#include "pub_core_vkiscnums_asm.h"
#include "libvex_guest_offsets.h"
Perform a syscall for the client. This will run a syscall
with the client's specific per-thread signal mask.
The structure of this function is such that, if the syscall is
interrupted by a signal, we can determine exactly what
execution state we were in with respect to the execution of
the syscall by examining the value of %eip in the signal
handler. This means that we can always do the appropriate
thing to precisely emulate the kernel's signal/syscall
The syscall number is taken from the argument, even though it
should also be in guest_state->guest_RAX. The syscall result
is written back to guest_state->guest_RAX on completion.
Returns 0 if the syscall was successfully called (even if the
syscall itself failed), or a -ve error code if one of the
sigprocmasks failed (there's no way to determine which one
VG_(fixup_guest_state_after_syscall_interrupted) does the
thread state fixup in the case where we were interrupted by a
Int ML_(do_syscall_for_client_WRK(
Int syscallno, // rdi
void* guest_state, // rsi
const vki_sigset_t *sysmask, // rdx
const vki_sigset_t *postmask, // rcx
Int sigsetSzB) // r8
/* from vki_arch.h */
.globl ML_(do_syscall_for_client_WRK)
/* save callee-saved regs */
pushq %rbx
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
#define FSZ ((4+1)*4) /* 4 args + ret addr */
#define PUSH_di_si_dx_cx_8 \
pushq %rdi ; \
pushq %rsi ; \
pushq %rdx ; \
pushq %rcx ; \
pushq %r8
#define POP_di_si_dx_cx_8 \
popq %r8 ; \
popq %rcx ; \
popq %rdx ; \
popq %rsi ; \
popq %rdi
1: /* Even though we can't take a signal until the sigprocmask completes,
start the range early.
If eip is in the range [1,2), the syscall hasn't been started yet */
/* Set the signal mask which should be current during the syscall. */
/* Save and restore all 5 arg regs round the call. This is easier
than figuring out the minimal set to save/restore. */
movq $__NR_rt_sigprocmask, %rax // syscall #
movq $VKI_SIG_SETMASK, %rdi // how
movq %rdx, %rsi // sysmask
movq %rcx, %rdx // postmask
movq %r8, %r10 // sigsetSzB
testq %rax, %rax
js 7f /* sigprocmask failed */
/* OK, that worked. Now do the syscall proper. */
movq %rsi, %rax /* rax --> VexGuestAMD64State * */
pushq %rdi /* syscallno -> stack */
movq OFFSET_amd64_RDI(%rax), %rdi
movq OFFSET_amd64_RSI(%rax), %rsi
movq OFFSET_amd64_RDX(%rax), %rdx
movq OFFSET_amd64_R10(%rax), %r10
movq OFFSET_amd64_R8(%rax), %r8
movq OFFSET_amd64_R9(%rax), %r9
popq %rax /* syscallno -> %rax */
/* If rip==2, then the syscall was either just about
to start, or was interrupted and the kernel was
restarting it. */
2: syscall
3: /* In the range [3, 4), the syscall result is in %rax,
but hasn't been committed to RAX. */
movq %rax, OFFSET_amd64_RAX(%rsi) /* save back to RAX */
4: /* Re-block signals. If eip is in [4,5), then the syscall
is complete and we needn't worry about it. */
movq $__NR_rt_sigprocmask, %rax // syscall #
movq $VKI_SIG_SETMASK, %rdi // how
movq %rcx, %rsi // postmask
xorq %rdx, %rdx // NULL
movq %r8, %r10 // sigsetSzB
testq %rax, %rax
js 7f /* sigprocmask failed */
5: /* now safe from signals */
movq $0, %rax /* SUCCESS */
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
7: /* failure: return 0x8000 | error code */
negq %rax
andq $0x7FFF, %rax
orq $0x8000, %rax
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
#undef FSZ
.section .rodata
/* export the ranges so that
VG_(fixup_guest_state_after_syscall_interrupted) can do the
right thing */
.globl ML_(blksys_setup)
.globl ML_(blksys_restart)
.globl ML_(blksys_complete)
.globl ML_(blksys_committed)
.globl ML_(blksys_finished)
ML_(blksys_setup): .quad 1b
ML_(blksys_restart): .quad 2b
ML_(blksys_complete): .quad 3b
ML_(blksys_committed): .quad 4b
ML_(blksys_finished): .quad 5b
/* Let the linker know we don't need an executable stack */
.section .note.GNU-stack,"",@progbits
#endif // defined(VGP_amd64_linux)
/*--- end ---*/