blob: c0df3d8ed7e716e38e912a028f9041fa906f190e [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Support for doing system calls. syscall-x86-solaris.S ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2011-2015 Petr Pavlu
setup@dagobah.cz
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "pub_core_basics_asm.h"
#if defined(VGP_x86_solaris)
#include "pub_core_vkiscnums_asm.h"
#include "libvex_guest_offsets.h"
/* From vki-solaris.h, checked at startup by m_vki.c. */
#define VKI_SIG_SETMASK 3
/* Prototype:
Int ML_(do_syscall_for_client_WRK)(
Int syscallno, // %ebp+8
void *guest_state, // %ebp+12
const vki_sigset_t *sysmask, // %ebp+16
const vki_sigset_t *postmask, // %ebp+20
UChar *cflag) // %ebp+24
*/
.macro ESTABLISH_STACKFRAME
/* Establish stack frame. */
pushl %ebp
movl %esp, %ebp
pushl %ebx /* save %ebx */
/* We'll use %ebx instead of %ebp to address the stack frame after the
door syscall is finished because %ebp is cleared by the syscall. */
movl %esp, %ebx /* %ebx = %ebp - 4 */
.endm
.macro UNBLOCK_SIGNALS
/* Set the signal mask which should be current during the syscall. */
/* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
pushl 20(%ebp)
pushl 16(%ebp)
pushl $VKI_SIG_SETMASK
pushl $0xcafebabe /* totally fake return address */
movl $__NR_sigprocmask, %eax
int $0x91
jc sigprocmask_failed /* sigprocmask failed */
addl $16, %esp
.endm
.macro REBLOCK_SIGNALS
/* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
pushl $0
pushl 20(%ebp)
pushl $VKI_SIG_SETMASK
pushl $0xcafef00d /* totally fake return address */
movl $__NR_sigprocmask, %eax
int $0x91
/* The syscall above changes the carry flag. This means that if the
syscall fails and we receive an interrupt after it then we've got
an invalid carry flag value in the fixup code. We don't care about
it because this syscall should never fail and if it does then we're
going to stop Valgrind anyway. */
jc sigprocmask_failed /* sigprocmask failed */
addl $16, %esp
.endm
.macro SIMPLE_RETURN
xorl %eax, %eax /* SUCCESS */
movl -4(%ebp), %ebx /* restore %ebx */
movl %ebp, %esp
popl %ebp
ret
.endm
sigprocmask_failed:
/* Failure: return 0x8000 | error code. */
/* Note that we enter here with %esp being 16 too low (4 extra words
on the stack). But because we're nuking the stack frame now, that
doesn't matter. */
andl $0x7FFF, %eax
orl $0x8000, %eax
movl -4(%ebp), %ebx /* restore %ebx */
movl %ebp, %esp
popl %ebp
ret
.globl ML_(do_syscall_for_client_WRK)
ML_(do_syscall_for_client_WRK):
ESTABLISH_STACKFRAME
1: /* Even though we can't take a signal until the sigprocmask completes,
start the range early. If %eip is in the range [1, 2), the syscall
hasn't been started yet. */
UNBLOCK_SIGNALS
/* Copy syscall parameters to the stack - assume no more than 8 plus
the return address. */
/* do_syscall8 */
movl 12(%ebp), %edx
movl OFFSET_x86_ESP(%edx), %edx /* %edx = simulated ESP */
movl 28+4(%edx), %eax
pushl %eax
movl 24+4(%edx), %eax
pushl %eax
movl 20+4(%edx), %eax
pushl %eax
movl 16+4(%edx), %eax
pushl %eax
movl 12+4(%edx), %eax
pushl %eax
movl 8+4(%edx), %eax
pushl %eax
movl 4+4(%edx), %eax
pushl %eax
movl 0+4(%edx), %eax
pushl %eax
/* Return address. */
movl 0(%edx), %eax
pushl %eax
/* Put syscall number in %eax. */
movl 8(%ebp), %eax
/* Do the syscall. Note that the Solaris kernel doesn't directly
restart syscalls! */
int $0x91
2: /* In the range [2, 3), the syscall result is in %eax and %edx and C,
but hasn't been committed to the thread state. If we get
interrupted in this section then we'll just use values saved in the
ucontext structure.
Important note for this and the following section: Don't add here
any code that alters the carry flag or worse, call any function.
That would completely break the fixup after an interrupt. */
movl 12(%ebp), %ecx
movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
movl 24(%ebp), %ecx
setc 0(%ecx) /* save returned carry flag */
3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
complete and we do not need to worry about it. We have to only
correctly save the carry flag. If we get interrupted in this
section then we just have to propagate the carry flag from the
ucontext structure to the thread state, %eax and %edx values are
already saved. */
REBLOCK_SIGNALS
4: /* Now safe from signals. */
SIMPLE_RETURN
.section .rodata
/* Export the ranges so that
VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
.globl ML_(blksys_setup)
.globl ML_(blksys_complete)
.globl ML_(blksys_committed)
.globl ML_(blksys_finished)
ML_(blksys_setup): .long 1b
ML_(blksys_complete): .long 2b
ML_(blksys_committed): .long 3b
ML_(blksys_finished): .long 4b
.previous
/* Prototype:
Int ML_(do_syscall_for_client_dret_WRK)(
Int syscallno, // %ebp+8 = %ebx+8+4
void *guest_state, // %ebp+12 = %ebx+12+4
const vki_sigset_t *sysmask, // %ebp+16 = %ebx+16+4
const vki_sigset_t *postmask, // %ebp+20 = %ebx+20+4
UChar *cflag) // %ebp+24 = %ebx+24+4
*/
/* Door_return is a very special call because the data are stored by the
kernel directly on the stack and the stack pointer is appropriately
modified by the kernel. Therefore we switch to the client stack before
doing the syscall, this is relatively trivial but an extra care has to be
taken when we get interrupted at some point. */
.globl ML_(do_syscall_for_client_dret_WRK)
ML_(do_syscall_for_client_dret_WRK):
ESTABLISH_STACKFRAME
1: /* Even though we can't take a signal until the sigprocmask completes,
start the range early. If %eip is in the range [1, 2), the syscall
hasn't been started yet. */
UNBLOCK_SIGNALS
/* Switch to the client stack. */
movl 12(%ebp), %edx
movl OFFSET_x86_ESP(%edx), %esp /* %esp = simulated ESP */
/* Change %ebp to a client value. It will always get committed by
the fixup code for range [2, 3) so it needs to be set to what the
client expects. */
movl OFFSET_x86_EBP(%edx), %ebp /* %ebp = simulated EBP */
/* Put syscall number in %eax. */
movl 8+4(%ebx), %eax
/* Do the syscall. Note that the Solaris kernel doesn't directly
restart syscalls! */
int $0x91
2: /* In the range [2, 3), the syscall result is in %eax, %edx, %esp and
%ebp and C, but hasn't been committed to the thread state. If we
get interrupted in this section then we'll just use values saved in
the ucontext structure.
Important note for this and the following section: Don't add here
any code that alters the carry flag or worse, call any function.
That would completely break the fixup after an interrupt. */
movl 12+4(%ebx), %ecx
movl %eax, OFFSET_x86_EAX(%ecx) /* save %eax to VEX */
movl %edx, OFFSET_x86_EDX(%ecx) /* save %edx to VEX */
movl %esp, OFFSET_x86_ESP(%ecx) /* save %esp to VEX */
movl %ebp, OFFSET_x86_EBP(%ecx) /* save %ebp to VEX */
movl 24+4(%ebx), %ecx
setc 0(%ecx) /* save returned carry flag */
movl %ebx, %esp /* switch to V stack */
3: /* Re-block signals. If %eip is in [3, 4), then the syscall is
complete and we do not need worry about it. We have to only
correctly save the carry flag. If we get interrupted in this
section then we just have to propagate the carry flag from the
ucontext structure to the thread state, %eax, %edx, %esp and %ebp
values are already saved. */
movl %ebx, %ebp
addl $4, %ebp
REBLOCK_SIGNALS
4: /* Now safe from signals. */
SIMPLE_RETURN
.section .rodata
.globl ML_(blksys_setup_DRET)
.globl ML_(blksys_complete_DRET)
.globl ML_(blksys_committed_DRET)
.globl ML_(blksys_finished_DRET)
ML_(blksys_setup_DRET): .long 1b
ML_(blksys_complete_DRET): .long 2b
ML_(blksys_committed_DRET): .long 3b
ML_(blksys_finished_DRET): .long 4b
.previous
#endif // defined(VGP_x86_solaris)
/* Let the linker know we don't need an executable stack */
MARK_STACK_NO_EXEC
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/