2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls. syscall-x86-solaris.S ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2011-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_x86_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, // %ebp+8
42 void *guest_state, // %ebp+12
43 const vki_sigset_t *sysmask, // %ebp+16
44 const vki_sigset_t *postmask, // %ebp+20
45 UChar *cflag) // %ebp+24
48 .macro ESTABLISH_STACKFRAME
49 /* Establish stack frame. */
52 pushl %ebx /* save %ebx */
54 /* We'll use %ebx instead of %ebp to address the stack frame after the
55 door syscall is finished because %ebp is cleared by the syscall. */
56 movl %esp, %ebx /* %ebx = %ebp - 4 */
59 .macro UNBLOCK_SIGNALS
60 /* Set the signal mask which should be current during the syscall. */
61 /* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
64 pushl $VKI_SIG_SETMASK
65 pushl $0xcafebabe /* totally fake return address */
66 movl $__NR_sigprocmask, %eax
68 jc sigprocmask_failed /* sigprocmask failed */
72 .macro REBLOCK_SIGNALS
73 /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
76 pushl $VKI_SIG_SETMASK
77 pushl $0xcafef00d /* totally fake return address */
78 movl $__NR_sigprocmask, %eax
80 /* The syscall above changes the carry flag. This means that if the
81 syscall fails and we receive an interrupt after it then we've got
82 an invalid carry flag value in the fixup code. We don't care about
83 it because this syscall should never fail and if it does then we're
84 going to stop Valgrind anyway. */
85 jc sigprocmask_failed /* sigprocmask failed */
90 xorl %eax, %eax /* SUCCESS */
91 movl -4(%ebp), %ebx /* restore %ebx */
98 /* Failure: return 0x8000 | error code. */
99 /* Note that we enter here with %esp being 16 too low (4 extra words
100 on the stack). But because we're nuking the stack frame now, that
104 movl -4(%ebp), %ebx /* restore %ebx */
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 %eip is in the range [1, 2), the syscall
115 hasn't been started yet. */
118 /* Copy syscall parameters to the stack - assume no more than 8 plus
119 the return address. */
122 movl OFFSET_x86_ESP(%edx), %edx /* %edx = simulated ESP */
123 movl 28+4(%edx), %eax
125 movl 24+4(%edx), %eax
127 movl 20+4(%edx), %eax
129 movl 16+4(%edx), %eax
131 movl 12+4(%edx), %eax
139 /* Return address. */
143 /* Put syscall number in %eax. */
146 /* Do the syscall. Note that the Solaris kernel doesn't directly
150 2: /* In the range [2, 3), the syscall result is in %eax and %edx and C,
151 but hasn't been committed to the thread state. If we get
152 interrupted in this section then we'll just use values saved in the
155 Important note for this and the following section: Don't add here
156 any code that alters the carry flag or worse, call any function.
157 That would completely break the fixup after an interrupt. */
159 movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
160 movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
162 setc 0(%ecx) /* save returned carry flag */
164 3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
165 complete and we do not need to worry about it. We have to only
166 correctly save the carry flag. If we get interrupted in this
167 section then we just have to propagate the carry flag from the
168 ucontext structure to the thread state, %eax and %edx values are
172 4: /* Now safe from signals. */
176 /* Export the ranges so that
177 VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
179 .globl ML_(blksys_setup)
180 .globl ML_(blksys_complete)
181 .globl ML_(blksys_committed)
182 .globl ML_(blksys_finished)
183 ML_(blksys_setup): .long 1b
184 ML_(blksys_complete): .long 2b
185 ML_(blksys_committed): .long 3b
186 ML_(blksys_finished): .long 4b
190 Int ML_(do_syscall_for_client_dret_WRK)(
191 Int syscallno, // %ebp+8 = %ebx+8+4
192 void *guest_state, // %ebp+12 = %ebx+12+4
193 const vki_sigset_t *sysmask, // %ebp+16 = %ebx+16+4
194 const vki_sigset_t *postmask, // %ebp+20 = %ebx+20+4
195 UChar *cflag) // %ebp+24 = %ebx+24+4
198 /* Door_return is a very special call because the data are stored by the
199 kernel directly on the stack and the stack pointer is appropriately
200 modified by the kernel. Therefore we switch to the client stack before
201 doing the syscall, this is relatively trivial but an extra care has to be
202 taken when we get interrupted at some point. */
204 .globl ML_(do_syscall_for_client_dret_WRK)
205 ML_(do_syscall_for_client_dret_WRK):
208 1: /* Even though we can't take a signal until the sigprocmask completes,
209 start the range early. If %eip is in the range [1, 2), the syscall
210 hasn't been started yet. */
213 /* Switch to the client stack. */
215 movl OFFSET_x86_ESP(%edx), %esp /* %esp = simulated ESP */
216 /* Change %ebp to a client value. It will always get committed by
217 the fixup code for range [2, 3) so it needs to be set to what the
219 movl OFFSET_x86_EBP(%edx), %ebp /* %ebp = simulated EBP */
221 /* Put syscall number in %eax. */
224 /* Do the syscall. Note that the Solaris kernel doesn't directly
228 2: /* In the range [2, 3), the syscall result is in %eax, %edx, %esp and
229 %ebp and C, but hasn't been committed to the thread state. If we
230 get interrupted in this section then we'll just use values saved in
231 the ucontext structure.
233 Important note for this and the following section: Don't add here
234 any code that alters the carry flag or worse, call any function.
235 That would completely break the fixup after an interrupt. */
236 movl 12+4(%ebx), %ecx
237 movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
238 movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
239 movl %esp, OFFSET_x86_ESP(%ecx) /* save %esp to VEX */
240 movl %ebp, OFFSET_x86_EBP(%ecx) /* save %ebp to VEX */
241 movl 24+4(%ebx), %ecx
242 setc 0(%ecx) /* save returned carry flag */
244 movl %ebx, %esp /* switch to V stack */
246 3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
247 complete and we do not need worry about it. We have to only
248 correctly save the carry flag. If we get interrupted in this
249 section then we just have to propagate the carry flag from the
250 ucontext structure to the thread state, %eax, %edx, %esp and %ebp
251 values are already saved. */
256 4: /* Now safe from signals. */
260 .globl ML_(blksys_setup_DRET)
261 .globl ML_(blksys_complete_DRET)
262 .globl ML_(blksys_committed_DRET)
263 .globl ML_(blksys_finished_DRET)
264 ML_(blksys_setup_DRET): .long 1b
265 ML_(blksys_complete_DRET): .long 2b
266 ML_(blksys_committed_DRET): .long 3b
267 ML_(blksys_finished_DRET): .long 4b
270 #endif // defined(VGP_x86_solaris)
272 /* Let the linker know we don't need an executable stack */
275 /*--------------------------------------------------------------------*/
277 /*--------------------------------------------------------------------*/