2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls. syscall-amd64-solaris.S ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2014-2017 Petr Pavlu
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
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. */
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 */
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). */
71 movq $VKI_SIG_SETMASK, %rdi
72 movq $__NR_sigprocmask, %rax
74 jc sigprocmask_failed /* sigprocmask failed */
77 .macro REBLOCK_SIGNALS
78 /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
81 movq $VKI_SIG_SETMASK, %rdi
82 movq $__NR_sigprocmask, %rax
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 */
93 xorq %rax, %rax /* SUCCESS */
94 movq -8(%rbp), %rbx /* restore %rbx */
101 /* Failure: return 0x8000 | error code. */
104 movq -8(%rbp), %rbx /* restore %rbx */
109 .globl ML_(do_syscall_for_client_WRK)
110 ML_(do_syscall_for_client_WRK):
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. */
118 /* Copy syscall parameters. */
120 /* 6 register parameters. */
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
134 /* Return address. */
138 /* Put syscall number in %rax. */
141 /* Do the syscall. Note that the Solaris kernel doesn't directly
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
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. */
154 movq %rax, OFFSET_amd64_RAX(%rcx) /* save %rax to VEX */
155 movq %rdx, OFFSET_amd64_RDX(%rcx) /* save %rdx to VEX */
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
167 4: /* Now safe from signals. */
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
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):
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. */
208 /* Prepare 6 register parameters. */
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
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
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. */
259 4: /* Now safe from signals. */
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
273 #endif // defined(VGP_amd64_solaris)
275 /* Let the linker know we don't need an executable stack */
278 /*--------------------------------------------------------------------*/
280 /*--------------------------------------------------------------------*/