Squash glibc warning about _BSD_SOURCE being deprecated tests.
[valgrind.git] / coregrind / m_syswrap / syscall-amd64-linux.S
blob80cc75cfc71267159a420056ea1c4f3595f3fe79
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-2015 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 #include "pub_core_basics_asm.h"
33 #if defined(VGP_amd64_linux)
35 #include "pub_core_vkiscnums_asm.h"
36 #include "libvex_guest_offsets.h"
39 /*----------------------------------------------------------------*/
41         Perform a syscall for the client.  This will run a syscall
42         with the client's specific per-thread signal mask.
43         
44         The structure of this function is such that, if the syscall is
45         interrupted by a signal, we can determine exactly what
46         execution state we were in with respect to the execution of
47         the syscall by examining the value of %eip in the signal
48         handler.  This means that we can always do the appropriate
49         thing to precisely emulate the kernel's signal/syscall
50         interactions.
52         The syscall number is taken from the argument, even though it
53         should also be in guest_state->guest_RAX.  The syscall result
54         is written back to guest_state->guest_RAX on completion.
55         
56         Returns 0 if the syscall was successfully called (even if the
57         syscall itself failed), or a -ve error code if one of the
58         sigprocmasks failed (there's no way to determine which one
59         failed).
61         VG_(fixup_guest_state_after_syscall_interrupted) does the
62         thread state fixup in the case where we were interrupted by a
63         signal.
64         
65         Prototype:
67         Int ML_(do_syscall_for_client_WRK(
68                                   Int syscallno,                // rdi
69                                   void* guest_state,            // rsi
70                                   const vki_sigset_t *sysmask,  // rdx
71                                   const vki_sigset_t *postmask, // rcx
72                                   Int sigsetSzB)                // r8
73                                    
76 /* from vki_arch.h */   
77 #define VKI_SIG_SETMASK 2
78         
79 .globl ML_(do_syscall_for_client_WRK)
80 ML_(do_syscall_for_client_WRK):
81         .cfi_startproc
82         /* save callee-saved regs */
83         pushq   %rbx
84         .cfi_adjust_cfa_offset 8
85         .cfi_offset %rbx, -16
86         pushq   %rbp
87         .cfi_adjust_cfa_offset 8
88         .cfi_offset %rbp, -24
89         pushq   %r12
90         .cfi_adjust_cfa_offset 8
91         .cfi_offset %r12, -32
92         pushq   %r13
93         .cfi_adjust_cfa_offset 8
94         .cfi_offset %r13, -40
95         pushq   %r14
96         .cfi_adjust_cfa_offset 8
97         .cfi_offset %r14, -48
98         pushq   %r15
99         .cfi_adjust_cfa_offset 8
100         .cfi_offset %r15, -56
102 #define FSZ     ((4+1)*4)       /* 4 args + ret addr */
104 #define PUSH_di_si_dx_cx_8         \
105         pushq   %rdi ;             \
106         .cfi_adjust_cfa_offset 8 ; \
107         pushq   %rsi ;             \
108         .cfi_adjust_cfa_offset 8 ; \
109         pushq   %rdx ;             \
110         .cfi_adjust_cfa_offset 8 ; \
111         pushq   %rcx ;             \
112         .cfi_adjust_cfa_offset 8 ; \
113         pushq   %r8 ;              \
114         .cfi_adjust_cfa_offset 8
116 #define POP_di_si_dx_cx_8           \
117         popq    %r8 ;               \
118         .cfi_adjust_cfa_offset -8 ; \
119         popq    %rcx ;              \
120         .cfi_adjust_cfa_offset -8 ; \
121         popq    %rdx ;              \
122         .cfi_adjust_cfa_offset -8 ; \
123         popq    %rsi ;              \
124         .cfi_adjust_cfa_offset -8 ; \
125         popq    %rdi ;              \
126         .cfi_adjust_cfa_offset -8
128 1:      /* Even though we can't take a signal until the sigprocmask completes,
129            start the range early.
130            If eip is in the range [1,2), the syscall hasn't been started yet */
132         /* Set the signal mask which should be current during the syscall. */
133         /* Save and restore all 5 arg regs round the call.  This is easier
134            than figuring out the minimal set to save/restore. */
136         PUSH_di_si_dx_cx_8
138         movq    $__NR_rt_sigprocmask, %rax      // syscall #
139         movq    $VKI_SIG_SETMASK, %rdi          // how
140         movq    %rdx, %rsi                      // sysmask
141         movq    %rcx, %rdx                      // postmask
142         movq    %r8, %r10                       // sigsetSzB
143         syscall
145         POP_di_si_dx_cx_8
146         
147         testq   %rax, %rax
148         js      7f      /* sigprocmask failed */
150         /* OK, that worked.  Now do the syscall proper. */
151         
152         PUSH_di_si_dx_cx_8
154         movq    %rsi, %rax      /* rax --> VexGuestAMD64State * */
155         pushq   %rdi            /* syscallno -> stack */
156         .cfi_adjust_cfa_offset 8
157         movq    OFFSET_amd64_RDI(%rax), %rdi
158         movq    OFFSET_amd64_RSI(%rax), %rsi
159         movq    OFFSET_amd64_RDX(%rax), %rdx
160         movq    OFFSET_amd64_R10(%rax), %r10
161         movq    OFFSET_amd64_R8(%rax), %r8
162         movq    OFFSET_amd64_R9(%rax), %r9
163         popq    %rax    /* syscallno -> %rax */
164         .cfi_adjust_cfa_offset -8
165         
166         /* If rip==2, then the syscall was either just about
167            to start, or was interrupted and the kernel was 
168            restarting it. */
169 2:      syscall
170 3:      /* In the range [3, 4), the syscall result is in %rax, 
171            but hasn't been committed to RAX. */
173         POP_di_si_dx_cx_8
175         movq    %rax, OFFSET_amd64_RAX(%rsi)    /* save back to RAX */
177 4:      /* Re-block signals.  If eip is in [4,5), then the syscall 
178            is complete and we needn't worry about it. */
180         PUSH_di_si_dx_cx_8
182         movq    $__NR_rt_sigprocmask, %rax      // syscall #
183         movq    $VKI_SIG_SETMASK, %rdi          // how
184         movq    %rcx, %rsi                      // postmask
185         xorq    %rdx, %rdx                      // NULL
186         movq    %r8, %r10                       // sigsetSzB
187         syscall
189         POP_di_si_dx_cx_8
191         testq   %rax, %rax
192         js      7f      /* sigprocmask failed */
194 5:      /* now safe from signals */
195         movq    $0, %rax        /* SUCCESS */
196         popq    %r15
197         .cfi_adjust_cfa_offset -8
198         popq    %r14
199         .cfi_adjust_cfa_offset -8
200         popq    %r13
201         .cfi_adjust_cfa_offset -8
202         popq    %r12
203         .cfi_adjust_cfa_offset -8
204         popq    %rbp
205         .cfi_adjust_cfa_offset -8
206         popq    %rbx
207         .cfi_adjust_cfa_offset -8
208         ret
209         .cfi_adjust_cfa_offset 6*8
211 7:      /* failure:      return 0x8000 | error code */
212         negq    %rax
213         andq    $0x7FFF, %rax
214         orq     $0x8000, %rax
215         popq    %r15
216         .cfi_adjust_cfa_offset -8
217         popq    %r14
218         .cfi_adjust_cfa_offset -8
219         popq    %r13
220         .cfi_adjust_cfa_offset -8
221         popq    %r12
222         .cfi_adjust_cfa_offset -8
223         popq    %rbp
224         .cfi_adjust_cfa_offset -8
225         popq    %rbx
226         .cfi_adjust_cfa_offset -8
227         ret
228         .cfi_endproc
229 #undef FSZ
231 .section .rodata
232 /* export the ranges so that
233    VG_(fixup_guest_state_after_syscall_interrupted) can do the
234    right thing */
235         
236 .globl ML_(blksys_setup)
237 .globl ML_(blksys_restart)
238 .globl ML_(blksys_complete)
239 .globl ML_(blksys_committed)
240 .globl ML_(blksys_finished)
241 ML_(blksys_setup):      .quad 1b
242 ML_(blksys_restart):    .quad 2b
243 ML_(blksys_complete):   .quad 3b
244 ML_(blksys_committed):  .quad 4b
245 ML_(blksys_finished):   .quad 5b
246 .previous
248 #endif // defined(VGP_amd64_linux)
250 /* Let the linker know we don't need an executable stack */
251 MARK_STACK_NO_EXEC
253 /*--------------------------------------------------------------------*/
254 /*--- end                                                          ---*/
255 /*--------------------------------------------------------------------*/