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, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 The GNU General Public License is contained in the file COPYING.
31 #include "pub_core_basics_asm.h"
33 #if defined(VGP_x86_solaris)
35 #include "pub_core_vkiscnums_asm.h"
36 #include "libvex_guest_offsets.h"
38 /* From vki-solaris.h, checked at startup by m_vki.c. */
39 #define VKI_SIG_SETMASK 3
42 Int ML_(do_syscall_for_client_WRK)(
43 Int syscallno, // %ebp+8
44 void *guest_state, // %ebp+12
45 const vki_sigset_t *sysmask, // %ebp+16
46 const vki_sigset_t *postmask, // %ebp+20
47 UChar *cflag) // %ebp+24
50 .macro ESTABLISH_STACKFRAME
51 /* Establish stack frame. */
54 pushl %ebx /* save %ebx */
56 /* We'll use %ebx instead of %ebp to address the stack frame after the
57 door syscall is finished because %ebp is cleared by the syscall. */
58 movl %esp, %ebx /* %ebx = %ebp - 4 */
61 .macro UNBLOCK_SIGNALS
62 /* Set the signal mask which should be current during the syscall. */
63 /* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
66 pushl $VKI_SIG_SETMASK
67 pushl $0xcafebabe /* totally fake return address */
68 movl $__NR_sigprocmask, %eax
70 jc sigprocmask_failed /* sigprocmask failed */
74 .macro REBLOCK_SIGNALS
75 /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
78 pushl $VKI_SIG_SETMASK
79 pushl $0xcafef00d /* totally fake return address */
80 movl $__NR_sigprocmask, %eax
82 /* The syscall above changes the carry flag. This means that if the
83 syscall fails and we receive an interrupt after it then we've got
84 an invalid carry flag value in the fixup code. We don't care about
85 it because this syscall should never fail and if it does then we're
86 going to stop Valgrind anyway. */
87 jc sigprocmask_failed /* sigprocmask failed */
92 xorl %eax, %eax /* SUCCESS */
93 movl -4(%ebp), %ebx /* restore %ebx */
100 /* Failure: return 0x8000 | error code. */
101 /* Note that we enter here with %esp being 16 too low (4 extra words
102 on the stack). But because we're nuking the stack frame now, that
106 movl -4(%ebp), %ebx /* restore %ebx */
111 .globl ML_(do_syscall_for_client_WRK)
112 ML_(do_syscall_for_client_WRK):
115 1: /* Even though we can't take a signal until the sigprocmask completes,
116 start the range early. If %eip is in the range [1, 2), the syscall
117 hasn't been started yet. */
120 /* Copy syscall parameters to the stack - assume no more than 8 plus
121 the return address. */
124 movl OFFSET_x86_ESP(%edx), %edx /* %edx = simulated ESP */
125 movl 28+4(%edx), %eax
127 movl 24+4(%edx), %eax
129 movl 20+4(%edx), %eax
131 movl 16+4(%edx), %eax
133 movl 12+4(%edx), %eax
141 /* Return address. */
145 /* Put syscall number in %eax. */
148 /* Do the syscall. Note that the Solaris kernel doesn't directly
152 2: /* In the range [2, 3), the syscall result is in %eax and %edx and C,
153 but hasn't been committed to the thread state. If we get
154 interrupted in this section then we'll just use values saved in the
157 Important note for this and the following section: Don't add here
158 any code that alters the carry flag or worse, call any function.
159 That would completely break the fixup after an interrupt. */
161 movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
162 movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
164 setc 0(%ecx) /* save returned carry flag */
166 3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
167 complete and we do not need to worry about it. We have to only
168 correctly save the carry flag. If we get interrupted in this
169 section then we just have to propagate the carry flag from the
170 ucontext structure to the thread state, %eax and %edx values are
174 4: /* Now safe from signals. */
178 /* Export the ranges so that
179 VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
181 .globl ML_(blksys_setup)
182 .globl ML_(blksys_complete)
183 .globl ML_(blksys_committed)
184 .globl ML_(blksys_finished)
185 ML_(blksys_setup): .long 1b
186 ML_(blksys_complete): .long 2b
187 ML_(blksys_committed): .long 3b
188 ML_(blksys_finished): .long 4b
192 Int ML_(do_syscall_for_client_dret_WRK)(
193 Int syscallno, // %ebp+8 = %ebx+8+4
194 void *guest_state, // %ebp+12 = %ebx+12+4
195 const vki_sigset_t *sysmask, // %ebp+16 = %ebx+16+4
196 const vki_sigset_t *postmask, // %ebp+20 = %ebx+20+4
197 UChar *cflag) // %ebp+24 = %ebx+24+4
200 /* Door_return is a very special call because the data are stored by the
201 kernel directly on the stack and the stack pointer is appropriately
202 modified by the kernel. Therefore we switch to the client stack before
203 doing the syscall, this is relatively trivial but an extra care has to be
204 taken when we get interrupted at some point. */
206 .globl ML_(do_syscall_for_client_dret_WRK)
207 ML_(do_syscall_for_client_dret_WRK):
210 1: /* Even though we can't take a signal until the sigprocmask completes,
211 start the range early. If %eip is in the range [1, 2), the syscall
212 hasn't been started yet. */
215 /* Switch to the client stack. */
217 movl OFFSET_x86_ESP(%edx), %esp /* %esp = simulated ESP */
218 /* Change %ebp to a client value. It will always get committed by
219 the fixup code for range [2, 3) so it needs to be set to what the
221 movl OFFSET_x86_EBP(%edx), %ebp /* %ebp = simulated EBP */
223 /* Put syscall number in %eax. */
226 /* Do the syscall. Note that the Solaris kernel doesn't directly
230 2: /* In the range [2, 3), the syscall result is in %eax, %edx, %esp and
231 %ebp and C, but hasn't been committed to the thread state. If we
232 get interrupted in this section then we'll just use values saved in
233 the ucontext structure.
235 Important note for this and the following section: Don't add here
236 any code that alters the carry flag or worse, call any function.
237 That would completely break the fixup after an interrupt. */
238 movl 12+4(%ebx), %ecx
239 movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
240 movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
241 movl %esp, OFFSET_x86_ESP(%ecx) /* save %esp to VEX */
242 movl %ebp, OFFSET_x86_EBP(%ecx) /* save %ebp to VEX */
243 movl 24+4(%ebx), %ecx
244 setc 0(%ecx) /* save returned carry flag */
246 movl %ebx, %esp /* switch to V stack */
248 3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
249 complete and we do not need worry about it. We have to only
250 correctly save the carry flag. If we get interrupted in this
251 section then we just have to propagate the carry flag from the
252 ucontext structure to the thread state, %eax, %edx, %esp and %ebp
253 values are already saved. */
258 4: /* Now safe from signals. */
262 .globl ML_(blksys_setup_DRET)
263 .globl ML_(blksys_complete_DRET)
264 .globl ML_(blksys_committed_DRET)
265 .globl ML_(blksys_finished_DRET)
266 ML_(blksys_setup_DRET): .long 1b
267 ML_(blksys_complete_DRET): .long 2b
268 ML_(blksys_committed_DRET): .long 3b
269 ML_(blksys_finished_DRET): .long 4b
272 #endif // defined(VGP_x86_solaris)
274 /* Let the linker know we don't need an executable stack */
277 /*--------------------------------------------------------------------*/
279 /*--------------------------------------------------------------------*/