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