1
2/*--------------------------------------------------------------------*/
3/*--- Support for doing system calls.        syscall-amd64-linux.S ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7  This file is part of Valgrind, a dynamic binary instrumentation
8  framework.
9
10  Copyright (C) 2000-2013 Julian Seward
11     jseward@acm.org
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#if defined(VGP_amd64_linux)
32
33#include "pub_core_basics_asm.h"
34#include "pub_core_vkiscnums_asm.h"
35#include "libvex_guest_offsets.h"
36
37
38/*----------------------------------------------------------------*/
39/*
40	Perform a syscall for the client.  This will run a syscall
41	with the client's specific per-thread signal mask.
42
43	The structure of this function is such that, if the syscall is
44	interrupted by a signal, we can determine exactly what
45	execution state we were in with respect to the execution of
46	the syscall by examining the value of %eip in the signal
47	handler.  This means that we can always do the appropriate
48	thing to precisely emulate the kernel's signal/syscall
49	interactions.
50
51	The syscall number is taken from the argument, even though it
52	should also be in guest_state->guest_RAX.  The syscall result
53	is written back to guest_state->guest_RAX on completion.
54
55	Returns 0 if the syscall was successfully called (even if the
56	syscall itself failed), or a -ve error code if one of the
57	sigprocmasks failed (there's no way to determine which one
58	failed).
59
60	VG_(fixup_guest_state_after_syscall_interrupted) does the
61	thread state fixup in the case where we were interrupted by a
62	signal.
63
64	Prototype:
65
66	Int ML_(do_syscall_for_client_WRK(
67	                          Int syscallno,		// rdi
68				  void* guest_state,		// rsi
69				  const vki_sigset_t *sysmask,	// rdx
70				  const vki_sigset_t *postmask,	// rcx
71				  Int sigsetSzB)		// r8
72
73*/
74
75/* from vki_arch.h */
76#define VKI_SIG_SETMASK	2
77
78.globl ML_(do_syscall_for_client_WRK)
79ML_(do_syscall_for_client_WRK):
80	/* save callee-saved regs */
81	pushq	%rbx
82	pushq	%rbp
83	pushq	%r12
84	pushq	%r13
85	pushq	%r14
86	pushq	%r15
87
88#define FSZ	((4+1)*4)	/* 4 args + ret addr */
89
90#define PUSH_di_si_dx_cx_8	\
91	pushq	%rdi ; 		\
92	pushq	%rsi ;		\
93	pushq	%rdx ;		\
94	pushq	%rcx ;		\
95	pushq	%r8
96
97#define	POP_di_si_dx_cx_8	\
98	popq	%r8 ;		\
99	popq	%rcx ;		\
100	popq	%rdx ;		\
101	popq	%rsi ;		\
102	popq	%rdi
103
1041:	/* Even though we can't take a signal until the sigprocmask completes,
105	   start the range early.
106	   If eip is in the range [1,2), the syscall hasn't been started yet */
107
108	/* Set the signal mask which should be current during the syscall. */
109	/* Save and restore all 5 arg regs round the call.  This is easier
110           than figuring out the minimal set to save/restore. */
111
112	PUSH_di_si_dx_cx_8
113
114	movq	$__NR_rt_sigprocmask, %rax	// syscall #
115	movq	$VKI_SIG_SETMASK, %rdi		// how
116	movq	%rdx, %rsi			// sysmask
117	movq	%rcx, %rdx			// postmask
118	movq	%r8, %r10			// sigsetSzB
119	syscall
120
121	POP_di_si_dx_cx_8
122
123	testq	%rax, %rax
124	js	7f	/* sigprocmask failed */
125
126	/* OK, that worked.  Now do the syscall proper. */
127
128	PUSH_di_si_dx_cx_8
129
130	movq	%rsi, %rax	/* rax --> VexGuestAMD64State * */
131	pushq	%rdi		/* syscallno -> stack */
132	movq	OFFSET_amd64_RDI(%rax), %rdi
133	movq	OFFSET_amd64_RSI(%rax), %rsi
134	movq	OFFSET_amd64_RDX(%rax), %rdx
135	movq	OFFSET_amd64_R10(%rax), %r10
136	movq	OFFSET_amd64_R8(%rax), %r8
137	movq	OFFSET_amd64_R9(%rax), %r9
138	popq	%rax	/* syscallno -> %rax */
139
140	/* If rip==2, then the syscall was either just about
141	   to start, or was interrupted and the kernel was
142	   restarting it. */
1432:	syscall
1443:	/* In the range [3, 4), the syscall result is in %rax,
145	   but hasn't been committed to RAX. */
146
147	POP_di_si_dx_cx_8
148
149	movq	%rax, OFFSET_amd64_RAX(%rsi)	/* save back to RAX */
150
1514:	/* Re-block signals.  If eip is in [4,5), then the syscall
152	   is complete and we needn't worry about it. */
153
154	PUSH_di_si_dx_cx_8
155
156	movq	$__NR_rt_sigprocmask, %rax	// syscall #
157	movq	$VKI_SIG_SETMASK, %rdi		// how
158	movq	%rcx, %rsi			// postmask
159	xorq	%rdx, %rdx			// NULL
160	movq	%r8, %r10			// sigsetSzB
161	syscall
162
163	POP_di_si_dx_cx_8
164
165	testq	%rax, %rax
166	js	7f	/* sigprocmask failed */
167
1685:	/* now safe from signals */
169	movq	$0, %rax	/* SUCCESS */
170	popq	%r15
171	popq	%r14
172	popq	%r13
173	popq	%r12
174	popq	%rbp
175	popq	%rbx
176	ret
177
1787:	/* failure:	 return 0x8000 | error code */
179	negq	%rax
180	andq	$0x7FFF, %rax
181	orq	$0x8000, %rax
182	popq	%r15
183	popq	%r14
184	popq	%r13
185	popq	%r12
186	popq	%rbp
187	popq	%rbx
188	ret
189#undef FSZ
190
191.section .rodata
192/* export the ranges so that
193   VG_(fixup_guest_state_after_syscall_interrupted) can do the
194   right thing */
195
196.globl ML_(blksys_setup)
197.globl ML_(blksys_restart)
198.globl ML_(blksys_complete)
199.globl ML_(blksys_committed)
200.globl ML_(blksys_finished)
201ML_(blksys_setup):	.quad 1b
202ML_(blksys_restart):	.quad 2b
203ML_(blksys_complete):	.quad 3b
204ML_(blksys_committed):	.quad 4b
205ML_(blksys_finished):	.quad 5b
206.previous
207
208/* Let the linker know we don't need an executable stack */
209.section .note.GNU-stack,"",@progbits
210
211#endif // defined(VGP_amd64_linux)
212
213/*--------------------------------------------------------------------*/
214/*--- end                                                          ---*/
215/*--------------------------------------------------------------------*/
216