Nicholas Nethercote f19fdbd136 Tweak type of VGA_(thread_syscall), and related variable name changes.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2793
2004-10-18 17:41:36 +00:00

175 lines
5.5 KiB
C

/*--------------------------------------------------------------------*/
/*--- x86/Linux-specific syscalls, etc. x86-linux/syscalls.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, an extensible x86 protected-mode
emulator for monitoring program execution on x86-Unixes.
Copyright (C) 2000-2004 Nicholas Nethercote
njn25@cam.ac.uk
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 "core.h"
/* We need our own copy of VG_(do_syscall)() to handle a special
race-condition. If we've got signals unblocked, and we take a
signal in the gap either just before or after the syscall, we may
end up not running the syscall at all, or running it more than
once.
The solution is to make the signal handler derive the proxy's
precise state by looking to see which eip it is executing at
exception time.
Ranges:
vga_sys_before ... vga_sys_restarted:
Setting up register arguments and running state. If
interrupted, then the syscall should be considered to return
ERESTARTSYS.
vga_sys_restarted:
If interrupted and eip==vga_sys_restarted, then either the syscall
was about to start running, or it has run, was interrupted and
the kernel wants to restart it. eax still contains the
syscall number. If interrupted, then the syscall return value
should be ERESTARTSYS.
vga_sys_after:
If interrupted and eip==vga_sys_after, the syscall either just
finished, or it was interrupted and the kernel doesn't want to
restart it. Either way, eax equals the correct return value
(either the actual return value, or EINTR).
vga_sys_after ... vga_sys_done:
System call is complete, but the state hasn't been updated,
nor has the result been written back. eax contains the return
value.
*/
extern void do_thread_syscall(Int sys,
Int arg1, Int arg2, Int arg3, Int arg4,
Int arg5, Int arg6,
Int *result, enum PXState *statep,
enum PXState poststate);
asm(
".text\n"
" .type do_thread_syscall,@function\n"
"do_thread_syscall:\n"
" push %esi\n"
" push %edi\n"
" push %ebx\n"
" push %ebp\n"
".vga_sys_before:\n"
" movl 16+ 4(%esp),%eax\n" /* syscall */
" movl 16+ 8(%esp),%ebx\n" /* arg1 */
" movl 16+12(%esp),%ecx\n" /* arg2 */
" movl 16+16(%esp),%edx\n" /* arg3 */
" movl 16+20(%esp),%esi\n" /* arg4 */
" movl 16+24(%esp),%edi\n" /* arg5 */
" movl 16+28(%esp),%ebp\n" /* arg6 */
".vga_sys_restarted:\n"
" int $0x80\n"
".vga_sys_after:\n"
" movl 16+32(%esp),%ebx\n" /* ebx = Int *res */
" movl %eax, (%ebx)\n" /* write the syscall retval */
" movl 16+36(%esp),%ebx\n" /* ebx = enum PXState * */
" testl %ebx, %ebx\n"
" jz 1f\n"
" movl 16+40(%esp),%ecx\n" /* write the post state (must be after retval write) */
" movl %ecx,(%ebx)\n"
".vga_sys_done:\n" /* OK, all clear from here */
"1: popl %ebp\n"
" popl %ebx\n"
" popl %edi\n"
" popl %esi\n"
" ret\n"
" .size do_thread_syscall,.-do_thread_syscall\n"
".previous\n"
".section .rodata\n"
" .globl vga_sys_before\n"
"vga_sys_before: .long .vga_sys_before\n"
" .globl vga_sys_restarted\n"
"vga_sys_restarted: .long .vga_sys_restarted\n"
" .globl vga_sys_after\n"
"vga_sys_after: .long .vga_sys_after\n"
" .globl vga_sys_done\n"
"vga_sys_done: .long .vga_sys_done\n"
".previous\n"
);
/* Run a syscall for a particular thread, getting the arguments from
the thread's registers, and returning the result in the thread's
eax.
Assumes that the only thread state which matters is the contents of
%eax-%ebp and the return value in %eax.
*/
void VGA_(thread_syscall)(Int syscallno, arch_thread_t *arch,
enum PXState *state , enum PXState poststate)
{
do_thread_syscall(syscallno, // syscall no.
arch->m_ebx, // arg 1
arch->m_ecx, // arg 2
arch->m_edx, // arg 3
arch->m_esi, // arg 4
arch->m_edi, // arg 5
arch->m_ebp, // arg 6
&arch->m_eax, // result
state, // state to update
poststate); // state when syscall has finished
}
// Back up to restart a system call.
void VGA_(restart_syscall)(arch_thread_t *arch)
{
arch->m_eip -= 2; // sizeof(int $0x80)
/* Make sure our caller is actually sane, and we're really backing
back over a syscall.
int $0x80 == CD 80
*/
{
UChar *p = (UChar *)arch->m_eip;
if (p[0] != 0xcd || p[1] != 0x80)
VG_(message)(Vg_DebugMsg,
"?! restarting over syscall at %p %02x %02x\n",
arch->m_eip, p[0], p[1]);
vg_assert(p[0] == 0xcd && p[1] == 0x80);
}
}
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/