drd: Add a consistency check
[valgrind.git] / coregrind / m_syswrap / syscall-amd64-linux.S
blob0810b5455d1d80aa8ce6df73fd96ea43bb207de9
2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls.        syscall-amd64-linux.S ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
10   Copyright (C) 2000-2013 Julian Seward 
11      jseward@acm.org
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.
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.
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.
28   The GNU General Public License is contained in the file COPYING.
31 #if defined(VGP_amd64_linux)
33 #include "pub_core_basics_asm.h"
34 #include "pub_core_vkiscnums_asm.h"
35 #include "libvex_guest_offsets.h"
38 /*----------------------------------------------------------------*/
40         Perform a syscall for the client.  This will run a syscall
41         with the client's specific per-thread signal mask.
42         
43         The structure of this function is such that, if the syscall is
44         interrupted by a signal, we can determine exactly what
45         execution state we were in with respect to the execution of
46         the syscall by examining the value of %eip in the signal
47         handler.  This means that we can always do the appropriate
48         thing to precisely emulate the kernel's signal/syscall
49         interactions.
51         The syscall number is taken from the argument, even though it
52         should also be in guest_state->guest_RAX.  The syscall result
53         is written back to guest_state->guest_RAX on completion.
54         
55         Returns 0 if the syscall was successfully called (even if the
56         syscall itself failed), or a -ve error code if one of the
57         sigprocmasks failed (there's no way to determine which one
58         failed).
60         VG_(fixup_guest_state_after_syscall_interrupted) does the
61         thread state fixup in the case where we were interrupted by a
62         signal.
63         
64         Prototype:
66         Int ML_(do_syscall_for_client_WRK(
67                                   Int syscallno,                // rdi
68                                   void* guest_state,            // rsi
69                                   const vki_sigset_t *sysmask,  // rdx
70                                   const vki_sigset_t *postmask, // rcx
71                                   Int sigsetSzB)                // r8
72                                    
75 /* from vki_arch.h */   
76 #define VKI_SIG_SETMASK 2
77         
78 .globl ML_(do_syscall_for_client_WRK)
79 ML_(do_syscall_for_client_WRK):
80         /* save callee-saved regs */
81         pushq   %rbx
82         pushq   %rbp
83         pushq   %r12
84         pushq   %r13
85         pushq   %r14
86         pushq   %r15
88 #define FSZ     ((4+1)*4)       /* 4 args + ret addr */
90 #define PUSH_di_si_dx_cx_8      \
91         pushq   %rdi ;          \
92         pushq   %rsi ;          \
93         pushq   %rdx ;          \
94         pushq   %rcx ;          \
95         pushq   %r8
97 #define POP_di_si_dx_cx_8       \
98         popq    %r8 ;           \
99         popq    %rcx ;          \
100         popq    %rdx ;          \
101         popq    %rsi ;          \
102         popq    %rdi
104 1:      /* Even though we can't take a signal until the sigprocmask completes,
105            start the range early.
106            If eip is in the range [1,2), the syscall hasn't been started yet */
108         /* Set the signal mask which should be current during the syscall. */
109         /* Save and restore all 5 arg regs round the call.  This is easier
110            than figuring out the minimal set to save/restore. */
112         PUSH_di_si_dx_cx_8
114         movq    $__NR_rt_sigprocmask, %rax      // syscall #
115         movq    $VKI_SIG_SETMASK, %rdi          // how
116         movq    %rdx, %rsi                      // sysmask
117         movq    %rcx, %rdx                      // postmask
118         movq    %r8, %r10                       // sigsetSzB
119         syscall
121         POP_di_si_dx_cx_8
122         
123         testq   %rax, %rax
124         js      7f      /* sigprocmask failed */
126         /* OK, that worked.  Now do the syscall proper. */
127         
128         PUSH_di_si_dx_cx_8
130         movq    %rsi, %rax      /* rax --> VexGuestAMD64State * */
131         pushq   %rdi            /* syscallno -> stack */
132         movq    OFFSET_amd64_RDI(%rax), %rdi
133         movq    OFFSET_amd64_RSI(%rax), %rsi
134         movq    OFFSET_amd64_RDX(%rax), %rdx
135         movq    OFFSET_amd64_R10(%rax), %r10
136         movq    OFFSET_amd64_R8(%rax), %r8
137         movq    OFFSET_amd64_R9(%rax), %r9
138         popq    %rax    /* syscallno -> %rax */
139         
140         /* If rip==2, then the syscall was either just about
141            to start, or was interrupted and the kernel was 
142            restarting it. */
143 2:      syscall
144 3:      /* In the range [3, 4), the syscall result is in %rax, 
145            but hasn't been committed to RAX. */
147         POP_di_si_dx_cx_8
149         movq    %rax, OFFSET_amd64_RAX(%rsi)    /* save back to RAX */
151 4:      /* Re-block signals.  If eip is in [4,5), then the syscall 
152            is complete and we needn't worry about it. */
154         PUSH_di_si_dx_cx_8
156         movq    $__NR_rt_sigprocmask, %rax      // syscall #
157         movq    $VKI_SIG_SETMASK, %rdi          // how
158         movq    %rcx, %rsi                      // postmask
159         xorq    %rdx, %rdx                      // NULL
160         movq    %r8, %r10                       // sigsetSzB
161         syscall
163         POP_di_si_dx_cx_8
165         testq   %rax, %rax
166         js      7f      /* sigprocmask failed */
168 5:      /* now safe from signals */
169         movq    $0, %rax        /* SUCCESS */
170         popq    %r15
171         popq    %r14
172         popq    %r13
173         popq    %r12
174         popq    %rbp
175         popq    %rbx
176         ret
178 7:      /* failure:      return 0x8000 | error code */
179         negq    %rax
180         andq    $0x7FFF, %rax
181         orq     $0x8000, %rax
182         popq    %r15
183         popq    %r14
184         popq    %r13
185         popq    %r12
186         popq    %rbp
187         popq    %rbx
188         ret
189 #undef FSZ
191 .section .rodata
192 /* export the ranges so that
193    VG_(fixup_guest_state_after_syscall_interrupted) can do the
194    right thing */
195         
196 .globl ML_(blksys_setup)
197 .globl ML_(blksys_restart)
198 .globl ML_(blksys_complete)
199 .globl ML_(blksys_committed)
200 .globl ML_(blksys_finished)
201 ML_(blksys_setup):      .quad 1b
202 ML_(blksys_restart):    .quad 2b
203 ML_(blksys_complete):   .quad 3b
204 ML_(blksys_committed):  .quad 4b
205 ML_(blksys_finished):   .quad 5b
206 .previous
208 /* Let the linker know we don't need an executable stack */
209 .section .note.GNU-stack,"",@progbits
211 #endif // defined(VGP_amd64_linux)
213 /*--------------------------------------------------------------------*/
214 /*--- end                                                          ---*/
215 /*--------------------------------------------------------------------*/