drd/drd_pthread_intercepts: Add a workaround for what is probably a compiler bug
[valgrind.git] / coregrind / m_syswrap / syscall-x86-solaris.S
blobb94f3479c6d1b1bfb2465e3ce5781fd93751d94f
2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls.        syscall-x86-solaris.S ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
10   Copyright (C) 2011-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_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
39 /* Prototype:
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. */
50         pushl   %ebp
51         movl    %esp, %ebp
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 */
57 .endm
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). */
62         pushl   20(%ebp)
63         pushl   16(%ebp)
64         pushl   $VKI_SIG_SETMASK
65         pushl   $0xcafebabe                     /* totally fake return address */
66         movl    $__NR_sigprocmask, %eax
67         int     $0x91
68         jc      sigprocmask_failed              /* sigprocmask failed */
69         addl    $16, %esp
70 .endm
72 .macro REBLOCK_SIGNALS
73         /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
74         pushl   $0
75         pushl   20(%ebp)
76         pushl   $VKI_SIG_SETMASK
77         pushl   $0xcafef00d                     /* totally fake return address */
78         movl    $__NR_sigprocmask, %eax
79         int     $0x91
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 */
86         addl    $16, %esp
87 .endm
89 .macro SIMPLE_RETURN
90         xorl    %eax, %eax                      /* SUCCESS */
91         movl    -4(%ebp), %ebx                  /* restore %ebx */
92         movl    %ebp, %esp
93         popl    %ebp
94         ret
95 .endm
97 sigprocmask_failed:
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
101            doesn't matter. */
102         andl    $0x7FFF, %eax
103         orl     $0x8000, %eax
104         movl    -4(%ebp), %ebx                  /* restore %ebx */
105         movl    %ebp, %esp
106         popl    %ebp
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 %eip is in the range [1, 2), the syscall
115            hasn't been started yet. */
116         UNBLOCK_SIGNALS
118         /* Copy syscall parameters to the stack - assume no more than 8 plus
119            the return address. */
120         /* do_syscall8 */
121         movl    12(%ebp), %edx
122         movl    OFFSET_x86_ESP(%edx), %edx      /* %edx = simulated ESP */
123         movl    28+4(%edx), %eax
124         pushl   %eax
125         movl    24+4(%edx), %eax
126         pushl   %eax
127         movl    20+4(%edx), %eax
128         pushl   %eax
129         movl    16+4(%edx), %eax
130         pushl   %eax
131         movl    12+4(%edx), %eax
132         pushl   %eax
133         movl    8+4(%edx), %eax
134         pushl   %eax
135         movl    4+4(%edx), %eax
136         pushl   %eax
137         movl    0+4(%edx), %eax
138         pushl   %eax
139         /* Return address. */
140         movl    0(%edx), %eax
141         pushl   %eax
143         /* Put syscall number in %eax. */
144         movl    8(%ebp), %eax
146         /* Do the syscall.  Note that the Solaris kernel doesn't directly
147            restart syscalls! */
148         int     $0x91
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
153            ucontext structure.
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. */
158         movl    12(%ebp), %ecx
159         movl    %eax, OFFSET_x86_EAX(%ecx)      /* save %eax to VEX */
160         movl    %edx, OFFSET_x86_EDX(%ecx)      /* save %edx to VEX */
161         movl    24(%ebp), %ecx
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
169            already saved. */
170         REBLOCK_SIGNALS
172 4:      /* Now safe from signals. */
173         SIMPLE_RETURN
175 .section .rodata
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
187 .previous
189 /* Prototype:
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):
206         ESTABLISH_STACKFRAME
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. */
211         UNBLOCK_SIGNALS
213         /* Switch to the client stack. */
214         movl    12(%ebp), %edx
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
218            client expects. */
219         movl    OFFSET_x86_EBP(%edx), %ebp      /* %ebp = simulated EBP */
221         /* Put syscall number in %eax. */
222         movl    8+4(%ebx), %eax
224         /* Do the syscall.  Note that the Solaris kernel doesn't directly
225            restart syscalls! */
226         int     $0x91
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. */
252         movl    %ebx, %ebp
253         addl    $4, %ebp
254         REBLOCK_SIGNALS
256 4:      /* Now safe from signals. */
257         SIMPLE_RETURN
259 .section .rodata
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
268 .previous
270 #endif // defined(VGP_x86_solaris)
272 /* Let the linker know we don't need an executable stack */
273 MARK_STACK_NO_EXEC
275 /*--------------------------------------------------------------------*/
276 /*--- end                                                          ---*/
277 /*--------------------------------------------------------------------*/