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-2017 Julian Seward 11 jseward (at) 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 #include "pub_core_basics_asm.h" 32 33 #if defined(VGP_amd64_linux) 34 35 #include "pub_core_vkiscnums_asm.h" 36 #include "libvex_guest_offsets.h" 37 38 39 /*----------------------------------------------------------------*/ 40 /* 41 Perform a syscall for the client. This will run a syscall 42 with the client's specific per-thread signal mask. 43 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 50 interactions. 51 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. 55 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 59 failed). 60 61 VG_(fixup_guest_state_after_syscall_interrupted) does the 62 thread state fixup in the case where we were interrupted by a 63 signal. 64 65 Prototype: 66 67 Int ML_(do_syscall_for_client_WRK( 68 Int syscallno, // rdi 69 void* guest_state, // rsi 70 const vki_sigset_t *sysmask, // rdx 71 const vki_sigset_t *postmask, // rcx 72 Int sigsetSzB) // r8 73 74 */ 75 76 /* from vki_arch.h */ 77 #define VKI_SIG_SETMASK 2 78 79 .globl ML_(do_syscall_for_client_WRK) 80 ML_(do_syscall_for_client_WRK): 81 .cfi_startproc 82 /* save callee-saved regs */ 83 pushq %rbx 84 .cfi_adjust_cfa_offset 8 85 .cfi_offset %rbx, -16 86 pushq %rbp 87 .cfi_adjust_cfa_offset 8 88 .cfi_offset %rbp, -24 89 pushq %r12 90 .cfi_adjust_cfa_offset 8 91 .cfi_offset %r12, -32 92 pushq %r13 93 .cfi_adjust_cfa_offset 8 94 .cfi_offset %r13, -40 95 pushq %r14 96 .cfi_adjust_cfa_offset 8 97 .cfi_offset %r14, -48 98 pushq %r15 99 .cfi_adjust_cfa_offset 8 100 .cfi_offset %r15, -56 101 102 #define FSZ ((4+1)*4) /* 4 args + ret addr */ 103 104 #define PUSH_di_si_dx_cx_8 \ 105 pushq %rdi ; \ 106 .cfi_adjust_cfa_offset 8 ; \ 107 pushq %rsi ; \ 108 .cfi_adjust_cfa_offset 8 ; \ 109 pushq %rdx ; \ 110 .cfi_adjust_cfa_offset 8 ; \ 111 pushq %rcx ; \ 112 .cfi_adjust_cfa_offset 8 ; \ 113 pushq %r8 ; \ 114 .cfi_adjust_cfa_offset 8 115 116 #define POP_di_si_dx_cx_8 \ 117 popq %r8 ; \ 118 .cfi_adjust_cfa_offset -8 ; \ 119 popq %rcx ; \ 120 .cfi_adjust_cfa_offset -8 ; \ 121 popq %rdx ; \ 122 .cfi_adjust_cfa_offset -8 ; \ 123 popq %rsi ; \ 124 .cfi_adjust_cfa_offset -8 ; \ 125 popq %rdi ; \ 126 .cfi_adjust_cfa_offset -8 127 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 */ 131 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. */ 135 136 PUSH_di_si_dx_cx_8 137 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 143 syscall 144 145 POP_di_si_dx_cx_8 146 147 testq %rax, %rax 148 js 7f /* sigprocmask failed */ 149 150 /* OK, that worked. Now do the syscall proper. */ 151 152 PUSH_di_si_dx_cx_8 153 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 165 166 /* If rip==2, then the syscall was either just about 167 to start, or was interrupted and the kernel was 168 restarting it. */ 169 2: syscall 170 3: /* In the range [3, 4), the syscall result is in %rax, 171 but hasn't been committed to RAX. */ 172 173 POP_di_si_dx_cx_8 174 175 movq %rax, OFFSET_amd64_RAX(%rsi) /* save back to RAX */ 176 177 4: /* Re-block signals. If eip is in [4,5), then the syscall 178 is complete and we needn't worry about it. */ 179 180 PUSH_di_si_dx_cx_8 181 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 187 syscall 188 189 POP_di_si_dx_cx_8 190 191 testq %rax, %rax 192 js 7f /* sigprocmask failed */ 193 194 5: /* now safe from signals */ 195 movq $0, %rax /* SUCCESS */ 196 popq %r15 197 .cfi_adjust_cfa_offset -8 198 popq %r14 199 .cfi_adjust_cfa_offset -8 200 popq %r13 201 .cfi_adjust_cfa_offset -8 202 popq %r12 203 .cfi_adjust_cfa_offset -8 204 popq %rbp 205 .cfi_adjust_cfa_offset -8 206 popq %rbx 207 .cfi_adjust_cfa_offset -8 208 ret 209 .cfi_adjust_cfa_offset 6*8 210 211 7: /* failure: return 0x8000 | error code */ 212 negq %rax 213 andq $0x7FFF, %rax 214 orq $0x8000, %rax 215 popq %r15 216 .cfi_adjust_cfa_offset -8 217 popq %r14 218 .cfi_adjust_cfa_offset -8 219 popq %r13 220 .cfi_adjust_cfa_offset -8 221 popq %r12 222 .cfi_adjust_cfa_offset -8 223 popq %rbp 224 .cfi_adjust_cfa_offset -8 225 popq %rbx 226 .cfi_adjust_cfa_offset -8 227 ret 228 .cfi_endproc 229 #undef FSZ 230 231 .section .rodata 232 /* export the ranges so that 233 VG_(fixup_guest_state_after_syscall_interrupted) can do the 234 right thing */ 235 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 246 .previous 247 248 #endif // defined(VGP_amd64_linux) 249 250 /* Let the linker know we don't need an executable stack */ 251 MARK_STACK_NO_EXEC 252 253 /*--------------------------------------------------------------------*/ 254 /*--- end ---*/ 255 /*--------------------------------------------------------------------*/ 256