1
2/*--------------------------------------------------------------------*/
3/*--- Support for doing system calls.        syscall-x86-solaris.S ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7  This file is part of Valgrind, a dynamic binary instrumentation
8  framework.
9
10  Copyright (C) 2011-2017 Petr Pavlu
11     setup@dagobah.cz
12
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.
17
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.
22
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
26  02111-1307, USA.
27
28  The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "pub_core_basics_asm.h"
32
33#if defined(VGP_x86_solaris)
34
35#include "pub_core_vkiscnums_asm.h"
36#include "libvex_guest_offsets.h"
37
38/* From vki-solaris.h, checked at startup by m_vki.c. */
39#define VKI_SIG_SETMASK 3
40
41/* Prototype:
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
48*/
49
50.macro ESTABLISH_STACKFRAME
51	/* Establish stack frame. */
52	pushl	%ebp
53	movl	%esp, %ebp
54	pushl	%ebx				/* save %ebx */
55
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 */
59.endm
60
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). */
64	pushl	20(%ebp)
65	pushl	16(%ebp)
66	pushl	$VKI_SIG_SETMASK
67	pushl	$0xcafebabe			/* totally fake return address */
68	movl	$__NR_sigprocmask, %eax
69	int	$0x91
70	jc	sigprocmask_failed		/* sigprocmask failed */
71	addl	$16, %esp
72.endm
73
74.macro REBLOCK_SIGNALS
75	/* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
76	pushl	$0
77	pushl	20(%ebp)
78	pushl	$VKI_SIG_SETMASK
79	pushl	$0xcafef00d			/* totally fake return address */
80	movl	$__NR_sigprocmask, %eax
81	int	$0x91
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 */
88	addl	$16, %esp
89.endm
90
91.macro SIMPLE_RETURN
92	xorl	%eax, %eax			/* SUCCESS */
93	movl	-4(%ebp), %ebx			/* restore %ebx */
94	movl	%ebp, %esp
95	popl	%ebp
96	ret
97.endm
98
99sigprocmask_failed:
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
103	   doesn't matter. */
104	andl	$0x7FFF, %eax
105	orl	$0x8000, %eax
106	movl	-4(%ebp), %ebx			/* restore %ebx */
107	movl	%ebp, %esp
108	popl	%ebp
109	ret
110
111.globl ML_(do_syscall_for_client_WRK)
112ML_(do_syscall_for_client_WRK):
113	ESTABLISH_STACKFRAME
114
1151:	/* 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. */
118	UNBLOCK_SIGNALS
119
120	/* Copy syscall parameters to the stack - assume no more than 8 plus
121	   the return address. */
122	/* do_syscall8 */
123	movl	12(%ebp), %edx
124	movl	OFFSET_x86_ESP(%edx), %edx	/* %edx = simulated ESP */
125	movl	28+4(%edx), %eax
126	pushl	%eax
127	movl	24+4(%edx), %eax
128	pushl	%eax
129	movl	20+4(%edx), %eax
130	pushl	%eax
131	movl	16+4(%edx), %eax
132	pushl	%eax
133	movl	12+4(%edx), %eax
134	pushl	%eax
135	movl	8+4(%edx), %eax
136	pushl	%eax
137	movl	4+4(%edx), %eax
138	pushl	%eax
139	movl	0+4(%edx), %eax
140	pushl	%eax
141	/* Return address. */
142	movl	0(%edx), %eax
143	pushl	%eax
144
145	/* Put syscall number in %eax. */
146	movl	8(%ebp), %eax
147
148	/* Do the syscall.  Note that the Solaris kernel doesn't directly
149	   restart syscalls! */
150	int	$0x91
151
1522:	/* 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
155	   ucontext structure.
156
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. */
160	movl	12(%ebp), %ecx
161	movl	%eax, OFFSET_x86_EAX(%ecx)	/* save %eax to VEX */
162	movl	%edx, OFFSET_x86_EDX(%ecx)	/* save %edx to VEX */
163	movl	24(%ebp), %ecx
164	setc	0(%ecx)				/* save returned carry flag */
165
1663:	/* 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
171	   already saved. */
172	REBLOCK_SIGNALS
173
1744:	/* Now safe from signals. */
175	SIMPLE_RETURN
176
177.section .rodata
178/* Export the ranges so that
179   VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
180
181.globl ML_(blksys_setup)
182.globl ML_(blksys_complete)
183.globl ML_(blksys_committed)
184.globl ML_(blksys_finished)
185ML_(blksys_setup):	.long 1b
186ML_(blksys_complete):	.long 2b
187ML_(blksys_committed):	.long 3b
188ML_(blksys_finished):	.long 4b
189.previous
190
191/* Prototype:
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
198*/
199
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. */
205
206.globl ML_(do_syscall_for_client_dret_WRK)
207ML_(do_syscall_for_client_dret_WRK):
208	ESTABLISH_STACKFRAME
209
2101:	/* 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. */
213	UNBLOCK_SIGNALS
214
215	/* Switch to the client stack. */
216	movl	12(%ebp), %edx
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
220	   client expects. */
221	movl	OFFSET_x86_EBP(%edx), %ebp	/* %ebp = simulated EBP */
222
223	/* Put syscall number in %eax. */
224	movl	8+4(%ebx), %eax
225
226	/* Do the syscall.  Note that the Solaris kernel doesn't directly
227	   restart syscalls! */
228	int	$0x91
229
2302:	/* 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.
234
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 */
245
246	movl	%ebx, %esp			/* switch to V stack */
247
2483:	/* 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. */
254	movl	%ebx, %ebp
255	addl	$4, %ebp
256	REBLOCK_SIGNALS
257
2584:	/* Now safe from signals. */
259	SIMPLE_RETURN
260
261.section .rodata
262.globl ML_(blksys_setup_DRET)
263.globl ML_(blksys_complete_DRET)
264.globl ML_(blksys_committed_DRET)
265.globl ML_(blksys_finished_DRET)
266ML_(blksys_setup_DRET):		.long 1b
267ML_(blksys_complete_DRET):	.long 2b
268ML_(blksys_committed_DRET):	.long 3b
269ML_(blksys_finished_DRET):	.long 4b
270.previous
271
272#endif // defined(VGP_x86_solaris)
273
274/* Let the linker know we don't need an executable stack */
275MARK_STACK_NO_EXEC
276
277/*--------------------------------------------------------------------*/
278/*--- end                                                          ---*/
279/*--------------------------------------------------------------------*/
280