2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls. syscall-amd64-linux.S ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2017 Julian Seward
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_amd64_linux)
35 #include "pub_core_vkiscnums_asm.h"
36 #include "libvex_guest_offsets.h"
39 /*----------------------------------------------------------------*/
41 Perform a syscall for the client. This will run a syscall
42 with the client's specific per-thread signal mask.
44 The structure of this function is such that, if the syscall is
45 interrupted by a signal, we can determine exactly what
46 execution state we were in with respect to the execution of
47 the syscall by examining the value of %eip in the signal
48 handler. This means that we can always do the appropriate
49 thing to precisely emulate the kernel's signal/syscall
52 The syscall number is taken from the argument, even though it
53 should also be in guest_state->guest_RAX. The syscall result
54 is written back to guest_state->guest_RAX on completion.
56 Returns 0 if the syscall was successfully called (even if the
57 syscall itself failed), or a -ve error code if one of the
58 sigprocmasks failed (there's no way to determine which one
61 VG_(fixup_guest_state_after_syscall_interrupted) does the
62 thread state fixup in the case where we were interrupted by a
67 Int ML_(do_syscall_for_client_WRK(
69 void* guest_state, // rsi
70 const vki_sigset_t *sysmask, // rdx
71 const vki_sigset_t *postmask, // rcx
77 #define VKI_SIG_SETMASK 2
79 .globl ML_(do_syscall_for_client_WRK)
80 ML_(do_syscall_for_client_WRK):
82 /* save callee-saved regs */
84 .cfi_adjust_cfa_offset 8
87 .cfi_adjust_cfa_offset 8
90 .cfi_adjust_cfa_offset 8
93 .cfi_adjust_cfa_offset 8
96 .cfi_adjust_cfa_offset 8
99 .cfi_adjust_cfa_offset 8
100 .cfi_offset %r15, -56
102 #define FSZ ((4+1)*4) /* 4 args + ret addr */
104 #define PUSH_di_si_dx_cx_8 \
106 .cfi_adjust_cfa_offset 8 ; \
108 .cfi_adjust_cfa_offset 8 ; \
110 .cfi_adjust_cfa_offset 8 ; \
112 .cfi_adjust_cfa_offset 8 ; \
114 .cfi_adjust_cfa_offset 8
116 #define POP_di_si_dx_cx_8 \
118 .cfi_adjust_cfa_offset -8 ; \
120 .cfi_adjust_cfa_offset -8 ; \
122 .cfi_adjust_cfa_offset -8 ; \
124 .cfi_adjust_cfa_offset -8 ; \
126 .cfi_adjust_cfa_offset -8
128 1: /* Even though we can't take a signal until the sigprocmask completes,
129 start the range early.
130 If eip is in the range [1,2), the syscall hasn't been started yet */
132 /* Set the signal mask which should be current during the syscall. */
133 /* Save and restore all 5 arg regs round the call. This is easier
134 than figuring out the minimal set to save/restore. */
138 movq $__NR_rt_sigprocmask, %rax // syscall #
139 movq $VKI_SIG_SETMASK, %rdi // how
140 movq %rdx, %rsi // sysmask
141 movq %rcx, %rdx // postmask
142 movq %r8, %r10 // sigsetSzB
148 js 7f /* sigprocmask failed */
150 /* OK, that worked. Now do the syscall proper. */
154 movq %rsi, %rax /* rax --> VexGuestAMD64State * */
155 pushq %rdi /* syscallno -> stack */
156 .cfi_adjust_cfa_offset 8
157 movq OFFSET_amd64_RDI(%rax), %rdi
158 movq OFFSET_amd64_RSI(%rax), %rsi
159 movq OFFSET_amd64_RDX(%rax), %rdx
160 movq OFFSET_amd64_R10(%rax), %r10
161 movq OFFSET_amd64_R8(%rax), %r8
162 movq OFFSET_amd64_R9(%rax), %r9
163 popq %rax /* syscallno -> %rax */
164 .cfi_adjust_cfa_offset -8
166 /* If rip==2, then the syscall was either just about
167 to start, or was interrupted and the kernel was
170 3: /* In the range [3, 4), the syscall result is in %rax,
171 but hasn't been committed to RAX. */
175 movq %rax, OFFSET_amd64_RAX(%rsi) /* save back to RAX */
177 4: /* Re-block signals. If eip is in [4,5), then the syscall
178 is complete and we needn't worry about it. */
182 movq $__NR_rt_sigprocmask, %rax // syscall #
183 movq $VKI_SIG_SETMASK, %rdi // how
184 movq %rcx, %rsi // postmask
185 xorq %rdx, %rdx // NULL
186 movq %r8, %r10 // sigsetSzB
192 js 7f /* sigprocmask failed */
194 5: /* now safe from signals */
195 movq $0, %rax /* SUCCESS */
197 .cfi_adjust_cfa_offset -8
199 .cfi_adjust_cfa_offset -8
201 .cfi_adjust_cfa_offset -8
203 .cfi_adjust_cfa_offset -8
205 .cfi_adjust_cfa_offset -8
207 .cfi_adjust_cfa_offset -8
209 .cfi_adjust_cfa_offset 6*8
211 7: /* failure: return 0x8000 | error code */
216 .cfi_adjust_cfa_offset -8
218 .cfi_adjust_cfa_offset -8
220 .cfi_adjust_cfa_offset -8
222 .cfi_adjust_cfa_offset -8
224 .cfi_adjust_cfa_offset -8
226 .cfi_adjust_cfa_offset -8
232 /* export the ranges so that
233 VG_(fixup_guest_state_after_syscall_interrupted) can do the
236 .globl ML_(blksys_setup)
237 .globl ML_(blksys_restart)
238 .globl ML_(blksys_complete)
239 .globl ML_(blksys_committed)
240 .globl ML_(blksys_finished)
241 ML_(blksys_setup): .quad 1b
242 ML_(blksys_restart): .quad 2b
243 ML_(blksys_complete): .quad 3b
244 ML_(blksys_committed): .quad 4b
245 ML_(blksys_finished): .quad 5b
248 #endif // defined(VGP_amd64_linux)
250 /* Let the linker know we don't need an executable stack */
253 /*--------------------------------------------------------------------*/
255 /*--------------------------------------------------------------------*/