FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_syswrap / syscall-amd64-solaris.S
blob14a7e0c5dd7deddec1425c565771b959a189234f
2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls.      syscall-amd64-solaris.S ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
10   Copyright (C) 2014-2017 Petr Pavlu
11      setup@dagobah.cz
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_solaris)
33 #include "pub_core_vkiscnums_asm.h"
34 #include "libvex_guest_offsets.h"
36 /* From vki-solaris.h, checked at startup by m_vki.c. */
37 #define VKI_SIG_SETMASK 3
39 /* Prototype:
40    Int ML_(do_syscall_for_client_WRK)(
41       Int syscallno,                    // %rdi = %rbp-48
42       void *guest_state,                // %rsi = %rbp-40
43       const vki_sigset_t *sysmask,      // %rdx = %rbp-32
44       const vki_sigset_t *postmask,     // %rcx = %rbp-24
45       UChar *cflag)                     // %r8 = %rbp-16
48 .macro ESTABLISH_STACKFRAME
49         /* Establish stack frame. */
50         pushq   %rbp
51         movq    %rsp, %rbp
52         pushq   %rbx                            /* save %rbx */
54         /* We'll use %rbx instead of %rbp to address the stack frame after the
55            door syscall is finished because %rbp is cleared by the syscall. */
56         movq    %rsp, %rbx                      /* %rbx = %rbp - 8 */
58         /* Push the parameters on the stack. */
59         pushq   %r8                             /* store %r8 at %rbp-16 */
60         pushq   %rcx                            /* store %rcx at %rbp-24 */
61         pushq   %rdx                            /* store %rdx at %rbp-32 */
62         pushq   %rsi                            /* store %rsi at %rbp-40 */
63         pushq   %rdi                            /* store %rdi at %rbp-48 */
64 .endm
66 .macro UNBLOCK_SIGNALS
67         /* Set the signal mask which should be current during the syscall. */
68         /* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
69         movq    -24(%rbp), %rdx
70         movq    -32(%rbp), %rsi
71         movq    $VKI_SIG_SETMASK, %rdi
72         movq    $__NR_sigprocmask, %rax
73         syscall
74         jc      sigprocmask_failed              /* sigprocmask failed */
75 .endm
77 .macro REBLOCK_SIGNALS
78         /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
79         movq    $0, %rdx
80         movq    -24(%rbp), %rsi
81         movq    $VKI_SIG_SETMASK, %rdi
82         movq    $__NR_sigprocmask, %rax
83         syscall
84         /* The syscall above changes the carry flag.  This means that if the
85            syscall fails and we receive an interrupt after it then we've got
86            an invalid carry flag value in the fixup code.  We don't care about
87            it because this syscall should never fail and if it does then we're
88            going to stop Valgrind anyway. */
89         jc      sigprocmask_failed              /* sigprocmask failed */
90 .endm
92 .macro SIMPLE_RETURN
93         xorq    %rax, %rax                      /* SUCCESS */
94         movq    -8(%rbp), %rbx                  /* restore %rbx */
95         movq    %rbp, %rsp
96         popq    %rbp
97         ret
98 .endm
100 sigprocmask_failed:
101         /* Failure: return 0x8000 | error code. */
102         andq    $0x7FFF, %rax
103         orq     $0x8000, %rax
104         movq    -8(%rbp), %rbx                  /* restore %rbx */
105         movq    %rbp, %rsp
106         popq    %rbp
107         ret
109 .globl ML_(do_syscall_for_client_WRK)
110 ML_(do_syscall_for_client_WRK):
111         ESTABLISH_STACKFRAME
113 1:      /* Even though we can't take a signal until the sigprocmask completes,
114            start the range early.  If %rip is in the range [1, 2), the syscall
115            hasn't been started yet. */
116         UNBLOCK_SIGNALS
118         /* Copy syscall parameters. */
119         /* do_syscall8 */
120         /* 6 register parameters. */
121         movq    -40(%rbp), %rax
122         movq    OFFSET_amd64_RDI(%rax), %rdi
123         movq    OFFSET_amd64_RSI(%rax), %rsi
124         movq    OFFSET_amd64_RDX(%rax), %rdx
125         movq    OFFSET_amd64_R10(%rax), %r10
126         movq    OFFSET_amd64_R8(%rax), %r8
127         movq    OFFSET_amd64_R9(%rax), %r9
128         /* 2 stack parameters. */
129         movq    OFFSET_amd64_RSP(%rax), %rax
130         movq    16(%rax), %r11
131         pushq   %r11
132         movq    8(%rax), %r11
133         pushq   %r11
134         /* Return address. */
135         movq    0(%rax), %r11
136         pushq   %r11
138         /* Put syscall number in %rax. */
139         movq    -48(%rbp), %rax
141         /* Do the syscall.  Note that the Solaris kernel doesn't directly
142            restart syscalls! */
143         syscall
145 2:      /* In the range [2, 3), the syscall result is in %rax and %rdx and C,
146            but hasn't been committed to the thread state.  If we get
147            interrupted in this section then we'll just use values saved in the
148            ucontext structure.
150            Important note for this and the following section: Don't add here
151            any code that alters the carry flag or worse, call any function.
152            That would completely break the fixup after an interrupt. */
153         movq    -40(%rbp), %rcx
154         movq    %rax, OFFSET_amd64_RAX(%rcx)    /* save %rax to VEX */
155         movq    %rdx, OFFSET_amd64_RDX(%rcx)    /* save %rdx to VEX */
156         movq    -16(%rbp), %rcx
157         setc    0(%rcx)                         /* save returned carry flag */
159 3:      /* Re-block signals. If %rip is in [3, 4), then the syscall is
160            complete and we do not need to worry about it.  We have to only
161            correctly save the carry flag.  If we get interrupted in this
162            section then we just have to propagate the carry flag from the
163            ucontext structure to the thread state, %rax and %rdx values are
164            already saved. */
165         REBLOCK_SIGNALS
167 4:      /* Now safe from signals. */
168         SIMPLE_RETURN
170 .section .rodata
171 /* Export the ranges so that
172    VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
174 .globl ML_(blksys_setup)
175 .globl ML_(blksys_complete)
176 .globl ML_(blksys_committed)
177 .globl ML_(blksys_finished)
178 ML_(blksys_setup):      .quad 1b
179 ML_(blksys_complete):   .quad 2b
180 ML_(blksys_committed):  .quad 3b
181 ML_(blksys_finished):   .quad 4b
182 .previous
184 /* Prototype:
185    Int ML_(do_syscall_for_client_dret_WRK)(
186       Int syscallno,                    // %rdi = %rbp-48 = %rbx-48+8
187       void *guest_state,                // %rsi = %rbp-40 = %rbx-40+8
188       const vki_sigset_t *sysmask,      // %rdx = %rbp-32 = %rbx-32+8
189       const vki_sigset_t *postmask,     // %rcx = %rbp-24 = %rbx-24+8
190       UChar *cflag)                     // %r8 = %rbp-16 = %rbx-16+8
193 /* Door_return is a very special call because the data are stored by the
194    kernel directly on the stack and the stack pointer is appropriately
195    modified by the kernel.  Therefore we switch to the client stack before
196    doing the syscall, this is relatively trivial but an extra care has to be
197    taken when we get interrupted at some point. */
199 .globl ML_(do_syscall_for_client_dret_WRK)
200 ML_(do_syscall_for_client_dret_WRK):
201         ESTABLISH_STACKFRAME
203 1:      /* Even though we can't take a signal until the sigprocmask completes,
204            start the range early.  If %rip is in the range [1, 2), the syscall
205            hasn't been started yet. */
206         UNBLOCK_SIGNALS
208         /* Prepare 6 register parameters. */
209         movq    -40(%rbp), %rax
210         movq    OFFSET_amd64_RDI(%rax), %rdi
211         movq    OFFSET_amd64_RSI(%rax), %rsi
212         movq    OFFSET_amd64_RDX(%rax), %rdx
213         movq    OFFSET_amd64_R10(%rax), %r10
214         movq    OFFSET_amd64_R8(%rax), %r8
215         movq    OFFSET_amd64_R9(%rax), %r9
217         /* Switch to the client stack. */
218         movq    OFFSET_amd64_RSP(%rax), %rsp    /* %rsp = simulated RSP */
219         /* Change %rbp to a client value. It will always get committed by
220            the fixup code for range [2, 3) so it needs to be set to what the
221            client expects. */
222         movq    OFFSET_amd64_RBP(%rax), %rbp    /* %rbp = simulated RBP */
224         /* Put syscall number in %rax. */
225         movq    -48+8(%rbx), %rax
227         /* Do the syscall.  Note that the Solaris kernel doesn't directly
228            restart syscalls! */
229         syscall
231 2:      /* In the range [2, 3), the syscall result is in %rax, %rdx, %rsp and
232            %rbp and C, but hasn't been committed to the thread state.  If we
233            get interrupted in this section then we'll just use values saved in
234            the ucontext structure.
236            Important note for this and the following section: Don't add here
237            any code that alters the carry flag or worse, call any function.
238            That would completely break the fixup after an interrupt. */
239         movq    -40+8(%rbx), %rcx
240         movq    %rax, OFFSET_amd64_RAX(%rcx)    /* save %rax to VEX */
241         movq    %rdx, OFFSET_amd64_RDX(%rcx)    /* save %rdx to VEX */
242         movq    %rsp, OFFSET_amd64_RSP(%rcx)    /* save %rsp to VEX */
243         movq    %rbp, OFFSET_amd64_RBP(%rcx)    /* save %rbp to VEX */
244         movq    -16+8(%rbx), %rcx
245         setc    0(%rcx)                         /* save returned carry flag */
247         movq    %rbx, %rsp                      /* switch to V stack */
249 3:      /* Re-block signals. If %rip is in [3, 4), then the syscall is
250            complete and we do not need worry about it.  We have to only
251            correctly save the carry flag.  If we get interrupted in this
252            section then we just have to propagate the carry flag from the
253            ucontext structure to the thread state, %rax, %rdx, %rsp and %rbp
254            values are already saved. */
255         movq    %rbx, %rbp
256         addq    $8, %rbp
257         REBLOCK_SIGNALS
259 4:      /* Now safe from signals. */
260         SIMPLE_RETURN
262 .section .rodata
263 .globl ML_(blksys_setup_DRET)
264 .globl ML_(blksys_complete_DRET)
265 .globl ML_(blksys_committed_DRET)
266 .globl ML_(blksys_finished_DRET)
267 ML_(blksys_setup_DRET):         .quad 1b
268 ML_(blksys_complete_DRET):      .quad 2b
269 ML_(blksys_committed_DRET):     .quad 3b
270 ML_(blksys_finished_DRET):      .quad 4b
271 .previous
273 #endif // defined(VGP_amd64_solaris)
275 /* Let the linker know we don't need an executable stack */
276 MARK_STACK_NO_EXEC
278 /*--------------------------------------------------------------------*/
279 /*--- end                                                          ---*/
280 /*--------------------------------------------------------------------*/