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