Support new faccessat2 linux syscall (439)
[valgrind.git] / coregrind / m_syswrap / syscall-x86-linux.S
blob2820bb9cc5c269e9108c2a5ce09eb04129ea4bcc
2 /*--------------------------------------------------------------------*/
3 /*--- Support for doing system calls.          syscall-x86-linux.S ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
10   Copyright (C) 2000-2017 Julian Seward 
11      jseward@acm.org
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.
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.
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, see <http://www.gnu.org/licenses/>.
26   The GNU General Public License is contained in the file COPYING.
29 #include "pub_core_basics_asm.h"
31 #if defined(VGP_x86_linux)
33 #include "pub_core_vkiscnums_asm.h"
34 #include "libvex_guest_offsets.h"
35                 
36         
37 /*----------------------------------------------------------------*/
39         Perform a syscall for the client.  This will run a syscall
40         with the client's specific per-thread signal mask.
41         
42         The structure of this function is such that, if the syscall is
43         interrupted by a signal, we can determine exactly what
44         execution state we were in with respect to the execution of
45         the syscall by examining the value of %eip in the signal
46         handler.  This means that we can always do the appropriate
47         thing to precisely emulate the kernel's signal/syscall
48         interactions.
50         The syscall number is taken from the argument, even though it
51         should also be in regs->m_eax.  The syscall result is written
52         back to regs->m_eax on completion.
53         
54         Returns 0 if the syscall was successfully called (even if the
55         syscall itself failed), or a nonzero error code in the lowest
56         8 bits if one of the sigprocmasks failed (there's no way to
57         determine which one failed).  And there's no obvious way to
58         recover from that either, but nevertheless we want to know.
60         VG_(fixup_guest_state_after_syscall_interrupted) does the
61         thread state fixup in the case where we were interrupted by a
62         signal.
63         
64         Prototype:
66         UWord ML_(do_syscall_for_client_WRK)(
67                                   Int syscallno,                // 0
68                                   void* guest_state,            // 4
69                                   const vki_sigset_t *sysmask,  // 8
70                                   const vki_sigset_t *postmask, // 12
71                                   Int sigsetSzB)                // 16
72                                    
75 /* from vki_arch.h */   
76 #define VKI_SIG_SETMASK 2
77         
78 .globl ML_(do_syscall_for_client_WRK)
79 ML_(do_syscall_for_client_WRK):
80         .cfi_startproc
81         /* save callee-saved regs */
82         push    %esi
83         .cfi_adjust_cfa_offset 4
84         .cfi_offset %esi, -8
85         push    %edi
86         .cfi_adjust_cfa_offset 4
87         .cfi_offset %esi, -12
88         push    %ebx
89         .cfi_adjust_cfa_offset 4
90         .cfi_offset %esi, -16
91         push    %ebp
92         .cfi_adjust_cfa_offset 4
93         .cfi_offset %esi, -20
94 #define FSZ     ((4+1)*4)       /* 4 args + ret addr */
96 1:      /* Even though we can't take a signal until the sigprocmask completes,
97            start the range early.
98            If eip is in the range [1,2), the syscall hasn't been started yet */
100         /* Set the signal mask which should be current during the syscall. */
101         movl    $ __NR_rt_sigprocmask, %eax
102         movl    $ VKI_SIG_SETMASK, %ebx
103         movl    8+FSZ(%esp), %ecx
104         movl    12+FSZ(%esp), %edx
105         movl    16+FSZ(%esp), %esi
106         int     $0x80
107         testl   %eax, %eax
108         js      7f      /* sigprocmask failed */
109         
110         movl     4+FSZ(%esp), %eax      /* eax == ThreadState * */
112         movl     OFFSET_x86_EBX(%eax), %ebx
113         movl     OFFSET_x86_ECX(%eax), %ecx
114         movl     OFFSET_x86_EDX(%eax), %edx
115         movl     OFFSET_x86_ESI(%eax), %esi
116         movl     OFFSET_x86_EDI(%eax), %edi
117         movl     OFFSET_x86_EBP(%eax), %ebp
118         movl     0+FSZ(%esp), %eax      /* use syscallno argument rather than thread EAX */
119         
120         /* If eip==2, then the syscall was either just about to start, 
121            or was interrupted and the kernel was restarting it. */
122 2:      int     $0x80
123 3:      /* In the range [3, 4), the syscall result is in %eax, but hasn't been
124            committed to EAX. */
125         movl    4+FSZ(%esp), %ebx
126         movl    %eax, OFFSET_x86_EAX(%ebx)      /* save back to EAX */
128 4:      /* Re-block signals.  If eip is in [4,5), then the syscall is complete and 
129            we needn't worry about it. */
130         movl    $ __NR_rt_sigprocmask, %eax
131         movl    $ VKI_SIG_SETMASK, %ebx
132         movl    12+FSZ(%esp), %ecx
133         xorl    %edx, %edx
134         movl    16+FSZ(%esp), %esi
135         int     $0x80
136         testl   %eax, %eax
137         js      7f      /* sigprocmask failed */
139 5:      /* now safe from signals */
140         movl    $0, %eax        /* SUCCESS */
141         popl    %ebp
142         .cfi_adjust_cfa_offset -4
143         popl    %ebx
144         .cfi_adjust_cfa_offset -4
145         popl    %edi
146         .cfi_adjust_cfa_offset -4
147         popl    %esi
148         .cfi_adjust_cfa_offset -4
149         ret
150         .cfi_adjust_cfa_offset 4*4
152 7:      /* failure: return 0x8000 | error code */
153         negl    %eax
154         andl    $0x7FFF, %eax
155         orl     $0x8000, %eax
156         popl    %ebp
157         .cfi_adjust_cfa_offset -4
158         popl    %ebx
159         .cfi_adjust_cfa_offset -4
160         popl    %edi
161         .cfi_adjust_cfa_offset -4
162         popl    %esi
163         .cfi_adjust_cfa_offset -4
164         ret
165         .cfi_endproc
166 #undef FSZ
168         
169 .section .rodata
170 /* export the ranges so that
171    VG_(fixup_guest_state_after_syscall_interrupted) can do the
172    right thing */
173         
174 .globl ML_(blksys_setup)
175 .globl ML_(blksys_restart)
176 .globl ML_(blksys_complete)
177 .globl ML_(blksys_committed)
178 .globl ML_(blksys_finished)
179 ML_(blksys_setup):      .long 1b
180 ML_(blksys_restart):    .long 2b
181 ML_(blksys_complete):   .long 3b
182 ML_(blksys_committed):  .long 4b
183 ML_(blksys_finished):   .long 5b
184 .previous
186 #endif // defined(VGP_x86_linux)
188 /* Let the linker know we don't need an executable stack */
189 MARK_STACK_NO_EXEC
191 /*--------------------------------------------------------------------*/
192 /*--- end                                                          ---*/
193 /*--------------------------------------------------------------------*/