1 2/*--------------------------------------------------------------------*/ 3/*--- Support for doing system calls. syscall-amd64-solaris.S ---*/ 4/*--------------------------------------------------------------------*/ 5 6/* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2014-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_amd64_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, // %rdi = %rbp-48 44 void *guest_state, // %rsi = %rbp-40 45 const vki_sigset_t *sysmask, // %rdx = %rbp-32 46 const vki_sigset_t *postmask, // %rcx = %rbp-24 47 UChar *cflag) // %r8 = %rbp-16 48*/ 49 50.macro ESTABLISH_STACKFRAME 51 /* Establish stack frame. */ 52 pushq %rbp 53 movq %rsp, %rbp 54 pushq %rbx /* save %rbx */ 55 56 /* We'll use %rbx instead of %rbp to address the stack frame after the 57 door syscall is finished because %rbp is cleared by the syscall. */ 58 movq %rsp, %rbx /* %rbx = %rbp - 8 */ 59 60 /* Push the parameters on the stack. */ 61 pushq %r8 /* store %r8 at %rbp-16 */ 62 pushq %rcx /* store %rcx at %rbp-24 */ 63 pushq %rdx /* store %rdx at %rbp-32 */ 64 pushq %rsi /* store %rsi at %rbp-40 */ 65 pushq %rdi /* store %rdi at %rbp-48 */ 66.endm 67 68.macro UNBLOCK_SIGNALS 69 /* Set the signal mask which should be current during the syscall. */ 70 /* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */ 71 movq -24(%rbp), %rdx 72 movq -32(%rbp), %rsi 73 movq $VKI_SIG_SETMASK, %rdi 74 movq $__NR_sigprocmask, %rax 75 syscall 76 jc sigprocmask_failed /* sigprocmask failed */ 77.endm 78 79.macro REBLOCK_SIGNALS 80 /* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */ 81 movq $0, %rdx 82 movq -24(%rbp), %rsi 83 movq $VKI_SIG_SETMASK, %rdi 84 movq $__NR_sigprocmask, %rax 85 syscall 86 /* The syscall above changes the carry flag. This means that if the 87 syscall fails and we receive an interrupt after it then we've got 88 an invalid carry flag value in the fixup code. We don't care about 89 it because this syscall should never fail and if it does then we're 90 going to stop Valgrind anyway. */ 91 jc sigprocmask_failed /* sigprocmask failed */ 92.endm 93 94.macro SIMPLE_RETURN 95 xorq %rax, %rax /* SUCCESS */ 96 movq -8(%rbp), %rbx /* restore %rbx */ 97 movq %rbp, %rsp 98 popq %rbp 99 ret 100.endm 101 102sigprocmask_failed: 103 /* Failure: return 0x8000 | error code. */ 104 andq $0x7FFF, %rax 105 orq $0x8000, %rax 106 movq -8(%rbp), %rbx /* restore %rbx */ 107 movq %rbp, %rsp 108 popq %rbp 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 %rip is in the range [1, 2), the syscall 117 hasn't been started yet. */ 118 UNBLOCK_SIGNALS 119 120 /* Copy syscall parameters. */ 121 /* do_syscall8 */ 122 /* 6 register parameters. */ 123 movq -40(%rbp), %rax 124 movq OFFSET_amd64_RDI(%rax), %rdi 125 movq OFFSET_amd64_RSI(%rax), %rsi 126 movq OFFSET_amd64_RDX(%rax), %rdx 127 movq OFFSET_amd64_R10(%rax), %r10 128 movq OFFSET_amd64_R8(%rax), %r8 129 movq OFFSET_amd64_R9(%rax), %r9 130 /* 2 stack parameters. */ 131 movq OFFSET_amd64_RSP(%rax), %rax 132 movq 16(%rax), %r11 133 pushq %r11 134 movq 8(%rax), %r11 135 pushq %r11 136 /* Return address. */ 137 movq 0(%rax), %r11 138 pushq %r11 139 140 /* Put syscall number in %rax. */ 141 movq -48(%rbp), %rax 142 143 /* Do the syscall. Note that the Solaris kernel doesn't directly 144 restart syscalls! */ 145 syscall 146 1472: /* In the range [2, 3), the syscall result is in %rax and %rdx and C, 148 but hasn't been committed to the thread state. If we get 149 interrupted in this section then we'll just use values saved in the 150 ucontext structure. 151 152 Important note for this and the following section: Don't add here 153 any code that alters the carry flag or worse, call any function. 154 That would completely break the fixup after an interrupt. */ 155 movq -40(%rbp), %rcx 156 movq %rax, OFFSET_amd64_RAX(%rcx) /* save %rax to VEX */ 157 movq %rdx, OFFSET_amd64_RDX(%rcx) /* save %rdx to VEX */ 158 movq -16(%rbp), %rcx 159 setc 0(%rcx) /* save returned carry flag */ 160 1613: /* Re-block signals. If %rip is in [3, 4), then the syscall is 162 complete and we do not need to worry about it. We have to only 163 correctly save the carry flag. If we get interrupted in this 164 section then we just have to propagate the carry flag from the 165 ucontext structure to the thread state, %rax and %rdx values are 166 already saved. */ 167 REBLOCK_SIGNALS 168 1694: /* Now safe from signals. */ 170 SIMPLE_RETURN 171 172.section .rodata 173/* Export the ranges so that 174 VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */ 175 176.globl ML_(blksys_setup) 177.globl ML_(blksys_complete) 178.globl ML_(blksys_committed) 179.globl ML_(blksys_finished) 180ML_(blksys_setup): .quad 1b 181ML_(blksys_complete): .quad 2b 182ML_(blksys_committed): .quad 3b 183ML_(blksys_finished): .quad 4b 184.previous 185 186/* Prototype: 187 Int ML_(do_syscall_for_client_dret_WRK)( 188 Int syscallno, // %rdi = %rbp-48 = %rbx-48+8 189 void *guest_state, // %rsi = %rbp-40 = %rbx-40+8 190 const vki_sigset_t *sysmask, // %rdx = %rbp-32 = %rbx-32+8 191 const vki_sigset_t *postmask, // %rcx = %rbp-24 = %rbx-24+8 192 UChar *cflag) // %r8 = %rbp-16 = %rbx-16+8 193*/ 194 195/* Door_return is a very special call because the data are stored by the 196 kernel directly on the stack and the stack pointer is appropriately 197 modified by the kernel. Therefore we switch to the client stack before 198 doing the syscall, this is relatively trivial but an extra care has to be 199 taken when we get interrupted at some point. */ 200 201.globl ML_(do_syscall_for_client_dret_WRK) 202ML_(do_syscall_for_client_dret_WRK): 203 ESTABLISH_STACKFRAME 204 2051: /* Even though we can't take a signal until the sigprocmask completes, 206 start the range early. If %rip is in the range [1, 2), the syscall 207 hasn't been started yet. */ 208 UNBLOCK_SIGNALS 209 210 /* Prepare 6 register parameters. */ 211 movq -40(%rbp), %rax 212 movq OFFSET_amd64_RDI(%rax), %rdi 213 movq OFFSET_amd64_RSI(%rax), %rsi 214 movq OFFSET_amd64_RDX(%rax), %rdx 215 movq OFFSET_amd64_R10(%rax), %r10 216 movq OFFSET_amd64_R8(%rax), %r8 217 movq OFFSET_amd64_R9(%rax), %r9 218 219 /* Switch to the client stack. */ 220 movq OFFSET_amd64_RSP(%rax), %rsp /* %rsp = simulated RSP */ 221 /* Change %rbp to a client value. It will always get committed by 222 the fixup code for range [2, 3) so it needs to be set to what the 223 client expects. */ 224 movq OFFSET_amd64_RBP(%rax), %rbp /* %rbp = simulated RBP */ 225 226 /* Put syscall number in %rax. */ 227 movq -48+8(%rbx), %rax 228 229 /* Do the syscall. Note that the Solaris kernel doesn't directly 230 restart syscalls! */ 231 syscall 232 2332: /* In the range [2, 3), the syscall result is in %rax, %rdx, %rsp and 234 %rbp and C, but hasn't been committed to the thread state. If we 235 get interrupted in this section then we'll just use values saved in 236 the ucontext structure. 237 238 Important note for this and the following section: Don't add here 239 any code that alters the carry flag or worse, call any function. 240 That would completely break the fixup after an interrupt. */ 241 movq -40+8(%rbx), %rcx 242 movq %rax, OFFSET_amd64_RAX(%rcx) /* save %rax to VEX */ 243 movq %rdx, OFFSET_amd64_RDX(%rcx) /* save %rdx to VEX */ 244 movq %rsp, OFFSET_amd64_RSP(%rcx) /* save %rsp to VEX */ 245 movq %rbp, OFFSET_amd64_RBP(%rcx) /* save %rbp to VEX */ 246 movq -16+8(%rbx), %rcx 247 setc 0(%rcx) /* save returned carry flag */ 248 249 movq %rbx, %rsp /* switch to V stack */ 250 2513: /* Re-block signals. If %rip is in [3, 4), then the syscall is 252 complete and we do not need worry about it. We have to only 253 correctly save the carry flag. If we get interrupted in this 254 section then we just have to propagate the carry flag from the 255 ucontext structure to the thread state, %rax, %rdx, %rsp and %rbp 256 values are already saved. */ 257 movq %rbx, %rbp 258 addq $8, %rbp 259 REBLOCK_SIGNALS 260 2614: /* Now safe from signals. */ 262 SIMPLE_RETURN 263 264.section .rodata 265.globl ML_(blksys_setup_DRET) 266.globl ML_(blksys_complete_DRET) 267.globl ML_(blksys_committed_DRET) 268.globl ML_(blksys_finished_DRET) 269ML_(blksys_setup_DRET): .quad 1b 270ML_(blksys_complete_DRET): .quad 2b 271ML_(blksys_committed_DRET): .quad 3b 272ML_(blksys_finished_DRET): .quad 4b 273.previous 274 275#endif // defined(VGP_amd64_solaris) 276 277/* Let the linker know we don't need an executable stack */ 278MARK_STACK_NO_EXEC 279 280/*--------------------------------------------------------------------*/ 281/*--- end ---*/ 282/*--------------------------------------------------------------------*/ 283