1 2/*--------------------------------------------------------------------*/ 3/*--- Support for doing system calls. syscall-x86-linux.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@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_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 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 nonzero error code in the lowest 58 8 bits if one of the sigprocmasks failed (there's no way to 59 determine which one failed). And there's no obvious way to 60 recover from that either, but nevertheless we want to know. 61 62 VG_(fixup_guest_state_after_syscall_interrupted) does the 63 thread state fixup in the case where we were interrupted by a 64 signal. 65 66 Prototype: 67 68 UWord ML_(do_syscall_for_client_WRK)( 69 Int syscallno, // 0 70 void* guest_state, // 4 71 const vki_sigset_t *sysmask, // 8 72 const vki_sigset_t *postmask, // 12 73 Int sigsetSzB) // 16 74 75*/ 76 77/* from vki_arch.h */ 78#define VKI_SIG_SETMASK 2 79 80.globl ML_(do_syscall_for_client_WRK) 81ML_(do_syscall_for_client_WRK): 82 .cfi_startproc 83 /* save callee-saved regs */ 84 push %esi 85 .cfi_adjust_cfa_offset 4 86 .cfi_offset %esi, -8 87 push %edi 88 .cfi_adjust_cfa_offset 4 89 .cfi_offset %esi, -12 90 push %ebx 91 .cfi_adjust_cfa_offset 4 92 .cfi_offset %esi, -16 93 push %ebp 94 .cfi_adjust_cfa_offset 4 95 .cfi_offset %esi, -20 96#define FSZ ((4+1)*4) /* 4 args + ret addr */ 97 981: /* Even though we can't take a signal until the sigprocmask completes, 99 start the range early. 100 If eip is in the range [1,2), the syscall hasn't been started yet */ 101 102 /* Set the signal mask which should be current during the syscall. */ 103 movl $ __NR_rt_sigprocmask, %eax 104 movl $ VKI_SIG_SETMASK, %ebx 105 movl 8+FSZ(%esp), %ecx 106 movl 12+FSZ(%esp), %edx 107 movl 16+FSZ(%esp), %esi 108 int $0x80 109 testl %eax, %eax 110 js 7f /* sigprocmask failed */ 111 112 movl 4+FSZ(%esp), %eax /* eax == ThreadState * */ 113 114 movl OFFSET_x86_EBX(%eax), %ebx 115 movl OFFSET_x86_ECX(%eax), %ecx 116 movl OFFSET_x86_EDX(%eax), %edx 117 movl OFFSET_x86_ESI(%eax), %esi 118 movl OFFSET_x86_EDI(%eax), %edi 119 movl OFFSET_x86_EBP(%eax), %ebp 120 movl 0+FSZ(%esp), %eax /* use syscallno argument rather than thread EAX */ 121 122 /* If eip==2, then the syscall was either just about to start, 123 or was interrupted and the kernel was restarting it. */ 1242: int $0x80 1253: /* In the range [3, 4), the syscall result is in %eax, but hasn't been 126 committed to EAX. */ 127 movl 4+FSZ(%esp), %ebx 128 movl %eax, OFFSET_x86_EAX(%ebx) /* save back to EAX */ 129 1304: /* Re-block signals. If eip is in [4,5), then the syscall is complete and 131 we needn't worry about it. */ 132 movl $ __NR_rt_sigprocmask, %eax 133 movl $ VKI_SIG_SETMASK, %ebx 134 movl 12+FSZ(%esp), %ecx 135 xorl %edx, %edx 136 movl 16+FSZ(%esp), %esi 137 int $0x80 138 testl %eax, %eax 139 js 7f /* sigprocmask failed */ 140 1415: /* now safe from signals */ 142 movl $0, %eax /* SUCCESS */ 143 popl %ebp 144 .cfi_adjust_cfa_offset -4 145 popl %ebx 146 .cfi_adjust_cfa_offset -4 147 popl %edi 148 .cfi_adjust_cfa_offset -4 149 popl %esi 150 .cfi_adjust_cfa_offset -4 151 ret 152 .cfi_adjust_cfa_offset 4*4 153 1547: /* failure: return 0x8000 | error code */ 155 negl %eax 156 andl $0x7FFF, %eax 157 orl $0x8000, %eax 158 popl %ebp 159 .cfi_adjust_cfa_offset -4 160 popl %ebx 161 .cfi_adjust_cfa_offset -4 162 popl %edi 163 .cfi_adjust_cfa_offset -4 164 popl %esi 165 .cfi_adjust_cfa_offset -4 166 ret 167 .cfi_endproc 168#undef FSZ 169 170 171.section .rodata 172/* export the ranges so that 173 VG_(fixup_guest_state_after_syscall_interrupted) can do the 174 right thing */ 175 176.globl ML_(blksys_setup) 177.globl ML_(blksys_restart) 178.globl ML_(blksys_complete) 179.globl ML_(blksys_committed) 180.globl ML_(blksys_finished) 181ML_(blksys_setup): .long 1b 182ML_(blksys_restart): .long 2b 183ML_(blksys_complete): .long 3b 184ML_(blksys_committed): .long 4b 185ML_(blksys_finished): .long 5b 186.previous 187 188#endif // defined(VGP_x86_linux) 189 190/* Let the linker know we don't need an executable stack */ 191MARK_STACK_NO_EXEC 192 193/*--------------------------------------------------------------------*/ 194/*--- end ---*/ 195/*--------------------------------------------------------------------*/ 196