1 2 /*--------------------------------------------------------------------*/ 3 /*--- Support for doing system calls. syscall-x86-darwin.S ---*/ 4 /*--------------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2015 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_x86_darwin) 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 regs->m_eax. The syscall result is written 54 back to regs->m_eax 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, // ebp+8 69 void* guest_state, // ebp+12 70 const vki_sigset_t *sysmask, // ebp+16 71 const vki_sigset_t *postmask, // ebp+20 72 Int sigsetSzB) // ebp+24 73 74 Note that sigsetSzB is totally ignored (and irrelevant). 75 */ 76 77 /* from vki-darwin.h, checked at startup by m_vki.c */ 78 #define VKI_SIG_SETMASK 3 79 80 /* DO_SYSCALL MACH|MDEP|UNIX */ 81 #define MACH 1 82 #define MDEP 2 83 #define UNIX 3 84 85 .macro DO_SYSCALL 86 /* establish stack frame */ 87 push %ebp 88 mov %esp, %ebp 89 subl $$8, %esp /* 16-byte align stack */ 90 91 L_$0_1: /* Even though we can't take a signal until the 92 __pthread_sigmask completes, start the range early. 93 If eip is in the range [1,2), the syscall hasn't been started yet */ 94 95 /* Set the signal mask which should be current during the syscall. */ 96 /* Set up for __pthread_sigmask(SIG_SETMASK, sysmask, postmask) */ 97 pushl 20(%ebp) 98 pushl 16(%ebp) 99 pushl $$VKI_SIG_SETMASK 100 pushl $$0xcafebabe /* totally fake return address */ 101 movl $$__NR___pthread_sigmask, %eax 102 int $$0x80 /* should be sysenter? */ 103 jc L_$0_7 /* __pthread_sigmask failed */ 104 addl $$16,%esp 105 106 /* Copy syscall parameters to the stack - assume no more than 8 107 * plus the return address */ 108 /* do_syscall8 */ 109 /* stack is currently aligned assuming 8 parameters */ 110 movl 12(%ebp), %edx 111 movl OFFSET_x86_ESP(%edx), %edx /* edx = simulated ESP */ 112 movl 28+4(%edx), %eax 113 pushl %eax 114 movl 24+4(%edx), %eax 115 pushl %eax 116 movl 20+4(%edx), %eax 117 pushl %eax 118 movl 16+4(%edx), %eax 119 pushl %eax 120 movl 12+4(%edx), %eax 121 pushl %eax 122 movl 8+4(%edx), %eax 123 pushl %eax 124 movl 4+4(%edx), %eax 125 pushl %eax 126 movl 0+4(%edx), %eax 127 pushl %eax 128 /* return address */ 129 movl 0(%edx), %eax 130 pushl %eax 131 132 /* Put syscall number in eax */ 133 movl 8(%ebp), %eax 134 135 /* If eip==2, then the syscall was either just about to start, 136 or was interrupted and the kernel was restarting it. */ 137 L_$0_2: 138 .if $0 == UNIX 139 int $$0x80 /* UNIX (GrP fixme should be sysenter?) */ 140 .elseif $0 == MACH 141 int $$0x81 142 .elseif $0 == MDEP 143 int $$0x82 144 .else 145 error$0 x 146 .endif 147 148 L_$0_3: /* In the range [3, 4), the syscall result is in %eax and %edx and C, 149 but hasn't been committed to the thread state. */ 150 setc 0(%esp) /* stash returned carry flag */ 151 movl 12(%ebp), %ecx 152 movl %eax, OFFSET_x86_EAX(%ecx) /* save EAX to vex */ 153 movl %edx, OFFSET_x86_EDX(%ecx) /* save EDX to vex */ 154 .if $0 == UNIX 155 /* UNIX: save carry flag to vex */ 156 subl $$12, %esp 157 movl %ecx, 4(%esp) 158 movl $$0, 0(%esp) 159 movb 12(%esp), %al 160 movb %al, 0(%esp) 161 call _LibVEX_GuestX86_put_eflag_c 162 addl $$12, %esp 163 .endif 164 165 L_$0_4: /* Re-block signals. If eip is in [4,5), then the syscall is 166 complete and we needn't worry about it. */ 167 /* Set up for __pthread_sigmask(SIG_SETMASK, postmask, NULL) */ 168 pushl $$0 169 pushl 20(%ebp) 170 pushl $$VKI_SIG_SETMASK 171 pushl $$0xcafef00d /* totally fake return address */ 172 movl $$__NR___pthread_sigmask, %eax 173 int $$0x80 /* should be sysenter? */ 174 jc L_$0_7 /* __pthread_sigmask failed */ 175 addl $$16,%esp 176 177 L_$0_5: /* now safe from signals */ 178 movl $$0, %eax /* SUCCESS */ 179 movl %ebp, %esp 180 popl %ebp 181 ret 182 183 L_$0_7: /* failure: return 0x8000 | error code */ 184 /* Note that we enter here with %esp being 16 too low 185 (4 extra words on the stack). But because we're nuking 186 the stack frame now, that doesn't matter. */ 187 andl $$0x7FFF, %eax 188 orl $$0x8000, %eax 189 movl %ebp, %esp 190 popl %ebp 191 ret 192 193 .endmacro 194 195 196 .globl ML_(do_syscall_for_client_unix_WRK) 197 ML_(do_syscall_for_client_unix_WRK): 198 DO_SYSCALL UNIX 199 200 .globl ML_(do_syscall_for_client_mach_WRK) 201 ML_(do_syscall_for_client_mach_WRK): 202 DO_SYSCALL MACH 203 204 .globl ML_(do_syscall_for_client_mdep_WRK) 205 ML_(do_syscall_for_client_mdep_WRK): 206 DO_SYSCALL MDEP 207 208 .data 209 /* export the ranges so that 210 VG_(fixup_guest_state_after_syscall_interrupted) can do the 211 right thing */ 212 213 /* eg MK_L_SCLASS_N(UNIX,99) produces L_3_99 214 since UNIX is #defined to 3 at the top of this file */ 215 #define FOO(scclass,labelno) L_##scclass##_##labelno 216 #define MK_L_SCCLASS_N(scclass,labelno) FOO(scclass,labelno) 217 218 .globl ML_(blksys_setup_MACH) 219 .globl ML_(blksys_restart_MACH) 220 .globl ML_(blksys_complete_MACH) 221 .globl ML_(blksys_committed_MACH) 222 .globl ML_(blksys_finished_MACH) 223 ML_(blksys_setup_MACH): .long MK_L_SCCLASS_N(MACH,1) 224 ML_(blksys_restart_MACH): .long MK_L_SCCLASS_N(MACH,2) 225 ML_(blksys_complete_MACH): .long MK_L_SCCLASS_N(MACH,3) 226 ML_(blksys_committed_MACH): .long MK_L_SCCLASS_N(MACH,4) 227 ML_(blksys_finished_MACH): .long MK_L_SCCLASS_N(MACH,5) 228 229 .globl ML_(blksys_setup_MDEP) 230 .globl ML_(blksys_restart_MDEP) 231 .globl ML_(blksys_complete_MDEP) 232 .globl ML_(blksys_committed_MDEP) 233 .globl ML_(blksys_finished_MDEP) 234 ML_(blksys_setup_MDEP): .long MK_L_SCCLASS_N(MDEP,1) 235 ML_(blksys_restart_MDEP): .long MK_L_SCCLASS_N(MDEP,2) 236 ML_(blksys_complete_MDEP): .long MK_L_SCCLASS_N(MDEP,3) 237 ML_(blksys_committed_MDEP): .long MK_L_SCCLASS_N(MDEP,4) 238 ML_(blksys_finished_MDEP): .long MK_L_SCCLASS_N(MDEP,5) 239 240 .globl ML_(blksys_setup_UNIX) 241 .globl ML_(blksys_restart_UNIX) 242 .globl ML_(blksys_complete_UNIX) 243 .globl ML_(blksys_committed_UNIX) 244 .globl ML_(blksys_finished_UNIX) 245 ML_(blksys_setup_UNIX): .long MK_L_SCCLASS_N(UNIX,1) 246 ML_(blksys_restart_UNIX): .long MK_L_SCCLASS_N(UNIX,2) 247 ML_(blksys_complete_UNIX): .long MK_L_SCCLASS_N(UNIX,3) 248 ML_(blksys_committed_UNIX): .long MK_L_SCCLASS_N(UNIX,4) 249 ML_(blksys_finished_UNIX): .long MK_L_SCCLASS_N(UNIX,5) 250 251 #endif // defined(VGP_x86_darwin) 252 253 /* Let the linker know we don't need an executable stack */ 254 MARK_STACK_NO_EXEC 255 256 /*--------------------------------------------------------------------*/ 257 /*--- end ---*/ 258 /*--------------------------------------------------------------------*/ 259