|
From: Jeremy F. <je...@go...> - 2005-01-17 22:33:04
|
CVS commit by fitzhardinge:
Call syscall POST functions when the syscall finishes as a result
of a signal. Mostly they're interrupted, but some syscalls complete
successfully, or at least write memory, when interrupted.
(Unrelated cleanup: remove duplicate VG_(clo_track_fds) tests in
vg_syscalls.c.)
A memcheck/tests/post-syscall.c 1.1 [no copyright]
A memcheck/tests/post-syscall.stderr.exp 1.1
A memcheck/tests/post-syscall.stdout.exp 1.1
A memcheck/tests/post-syscall.vgtest 1.1
M +15 -5 coregrind/core.h 1.67
M +2 -0 coregrind/vg_scheduler.c 1.212
M +6 -2 coregrind/vg_signals.c 1.111
M +90 -61 coregrind/vg_syscalls.c 1.233
M +23 -9 coregrind/x86-linux/syscalls.c 1.16
M +3 -0 memcheck/tests/Makefile.am 1.64
--- valgrind/memcheck/tests/Makefile.am #1.63:1.64
@@ -50,4 +50,5 @@
null_socket.stderr.exp null_socket.vgtest \
overlap.stderr.exp overlap.stdout.exp overlap.vgtest \
+ post-syscall.stderr.exp post-syscall.stderr.out post-syscall.vgtest \
pth_once.stderr.exp pth_once.stdout.exp pth_once.vgtest \
realloc1.stderr.exp realloc1.vgtest \
@@ -87,4 +88,5 @@
nanoleak new_nothrow \
null_socket overlap \
+ post-syscall \
realloc1 realloc2 realloc3 \
scalar scalar_exit_group scalar_fork scalar_supp scalar_vfork \
@@ -138,4 +140,5 @@
null_socket_SOURCES = null_socket.c
overlap_SOURCES = overlap.c
+post_syscall_SOURCES = post-syscall.c
realloc1_SOURCES = realloc1.c
realloc2_SOURCES = realloc2.c
--- valgrind/coregrind/core.h #1.66:1.67
@@ -656,4 +656,12 @@ struct _ThreadState {
struct SigQueue *sig_queue;
+ /* Syscall the Thread is currently running; -1 if none. Should only
+ be set while Thread is in VgTs_WaitSys. */
+ Int syscallno;
+
+ /* A value the Tool wants to pass from its pre-syscall to its
+ post-syscall function. */
+ void *tool_pre_syscall_value;
+
/* Stacks. When a thread slot is freed, we don't deallocate its
stack; we just leave it lying around for the next use of the
@@ -1259,4 +1267,6 @@ extern Char *VG_(resolve_filename)(Int f
extern void VG_(client_syscall) ( ThreadId tid );
+extern void VG_(post_syscall) ( ThreadId tid );
+
extern Bool VG_(is_kerror) ( Word res );
@@ -1827,9 +1837,9 @@ extern void VGA_(client_syscall)(Int sys
/*
Fix up the thread's state because a syscall may have been
- interrupted with a signal. Returns True if a syscall was hit by a
- signal, and the appropriate adjustment has been made to the
- thread's state, or False if not.
+ interrupted with a signal. Returns True if the syscall completed
+ (either interrupted or finished normally), or False if it was
+ restarted (or the signal didn't actually interrupt a syscall).
*/
-extern Bool VGA_(interrupted_syscall)(arch_thread_t *th_regs,
+extern void VGA_(interrupted_syscall)(ThreadId tid,
struct vki_ucontext *uc,
Bool restart);
--- valgrind/coregrind/vg_scheduler.c #1.211:1.212
@@ -557,4 +557,6 @@ void mostly_clear_thread_record ( Thread
VG_(threads)[tid].status = VgTs_Zombie;
+ VG_(threads)[tid].syscallno = -1;
+
VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
--- valgrind/coregrind/vg_signals.c #1.110:1.111
@@ -951,4 +951,8 @@ static void fill_prpsinfo(const ThreadSt
break;
+ case VgTs_Zombie:
+ prpsinfo->pr_sname = 'Z';
+ break;
+
case VgTs_Empty:
case VgTs_Init:
@@ -1557,6 +1561,6 @@ void vg_async_signalhandler ( Int sigNo,
sigNo, tid, info->si_code);
- /* Update thread state properly if this signal happened in or around a syscall */
- VGA_(interrupted_syscall)(&tst->arch, uc,
+ /* Update thread state properly */
+ VGA_(interrupted_syscall)(tid, uc,
!!(vg_scss.scss_per_sig[sigNo].scss_flags & VKI_SA_RESTART));
--- valgrind/coregrind/vg_syscalls.c #1.232:1.233
@@ -405,4 +405,7 @@ void record_fd_close(Int tid, Int fd)
OpenFd *i = allocated_fds;
+ if (!VG_(clo_track_fds))
+ return;
+
if (fd >= VG_(fd_hard_limit))
return; /* Valgrind internal */
@@ -437,4 +440,7 @@ void VG_(record_fd_open)(Int tid, Int fd
OpenFd *i;
+ if (!VG_(clo_track_fds))
+ return;
+
if (fd >= VG_(fd_hard_limit))
return; /* Valgrind internal */
@@ -636,5 +642,4 @@ void VG_(init_preopened_fds)()
if(fno != f)
- if(VG_(clo_track_fds))
VG_(record_fd_open)(-1, fno, VG_(resolve_filename)(fno));
}
@@ -760,5 +765,4 @@ void check_cmsg_for_fds(Int tid, struct
for (i = 0; i < fdc; i++)
- if(VG_(clo_track_fds))
// XXX: must we check the range on these fds with
// VG_(fd_allowed)()?
@@ -1907,5 +1911,5 @@ PRE(sys_close, 0)
POST(sys_close)
{
- if (VG_(clo_track_fds)) record_fd_close(tid, arg1);
+ record_fd_close(tid, arg1);
}
@@ -1922,5 +1926,4 @@ POST(sys_dup)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(resolve_filename)(SYSRES));
}
@@ -1937,5 +1940,4 @@ PRE(sys_dup2, 0)
POST(sys_dup2)
{
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(resolve_filename)(SYSRES));
}
@@ -1976,5 +1978,4 @@ POST(sys_fcntl)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(resolve_filename)(SYSRES));
}
@@ -2040,5 +2041,4 @@ POST(sys_fcntl64)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(resolve_filename)(SYSRES));
}
@@ -4381,5 +4381,4 @@ POST(sys_open)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(arena_strdup)(VG_AR_CORE, (Char*)arg1));
}
@@ -4427,5 +4426,4 @@ POST(sys_creat)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(arena_strdup)(VG_AR_CORE, (Char*)arg1));
}
@@ -4452,9 +4450,7 @@ POST(sys_pipe)
} else {
POST_MEM_WRITE( arg1, 2*sizeof(int) );
- if (VG_(clo_track_fds)) {
VG_(record_fd_open)(tid, p[0], NULL);
VG_(record_fd_open)(tid, p[1], NULL);
}
- }
}
@@ -4959,9 +4955,7 @@ POST(sys_socketcall)
} else {
POST_MEM_WRITE( ((UWord*)arg2)[3], 2*sizeof(int) );
- if (VG_(clo_track_fds)) {
VG_(record_fd_open)(tid, fd1, NULL);
VG_(record_fd_open)(tid, fd2, NULL);
}
- }
break;
}
@@ -4972,5 +4966,4 @@ POST(sys_socketcall)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, NULL);
}
@@ -4998,5 +4991,4 @@ POST(sys_socketcall)
buf_and_len_post_check ( tid, SYSRES, addr_p, addrlen_p,
"socketcall.accept(addrlen_out)" );
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, NULL);
}
@@ -5619,5 +5611,4 @@ POST(sys_mq_open)
set_result( -VKI_EMFILE );
} else {
- if (VG_(clo_track_fds))
VG_(record_fd_open)(tid, SYSRES, VG_(arena_strdup)(VG_AR_CORE, (Char*)arg1));
}
@@ -5835,4 +5826,60 @@ static const struct SyscallTableEntry ba
{ &bad_flags, bad_before, NULL };
+static const struct SyscallTableEntry *get_syscall_entry(UInt syscallno)
+{
+ const struct SyscallTableEntry *sys;
+
+ if (syscallno < VGA_(syscall_table_size) &&
+ VGA_(syscall_table)[syscallno].before != NULL)
+ sys = &VGA_(syscall_table)[syscallno];
+ else
+ sys = &bad_sys;
+
+ return sys;
+}
+
+/* Perform post-syscall actions */
+void VG_(post_syscall) (ThreadId tid)
+{
+ const struct SyscallTableEntry *sys;
+ UInt flags;
+ Bool mayBlock;
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ Int syscallno;
+
+ vg_assert(VG_(is_running_thread)(tid));
+
+ syscallno = tst->syscallno;
+ tst->syscallno = -1;
+
+ vg_assert(syscallno != -1);
+
+ sys = get_syscall_entry(syscallno);
+ flags = *(sys->flags_ptr);
+
+ mayBlock = !!( flags & MayBlock );
+
+
+ if (sys->after != NULL &&
+ ((flags & PostOnFail) != 0 || !VG_(is_kerror)(SYSRES))) {
+ if (0)
+ VG_(printf)("post_syscall: calling sys_after tid=%d syscallno=%d\n",
+ tid, syscallno);
+ (sys->after)(tid, tst);
+ }
+
+ /* Do any post-syscall actions
+
+ NOTE: this is only called if the syscall completed. If the
+ syscall was restarted, then it will call the Tool's
+ pre_syscall again, without calling post_syscall (ie, more
+ pre's than post's) */
+ if (VG_(needs).syscall_wrapper) {
+ VGP_PUSHCC(VgpSkinSysWrap);
+ SK_(post_syscall)(tid, syscallno, tst->tool_pre_syscall_value, SYSRES, mayBlock);
+ VGP_POPCC(VgpSkinSysWrap);
+ }
+}
+
void VG_(client_syscall) ( ThreadId tid )
{
@@ -5840,7 +5887,6 @@ void VG_(client_syscall) ( ThreadId tid
UInt syscallno, flags;
const struct SyscallTableEntry *sys;
- Bool isSpecial = False;
- Bool mayBlock = False;
- void *pre_result = 0;
+ Bool isSpecial;
+ Bool mayBlock;
VGP_PUSHCC(VgpCoreSysWrap);
@@ -5850,6 +5896,4 @@ void VG_(client_syscall) ( ThreadId tid
syscallno = (UInt)SYSNO;
- vg_assert(tst->status == VgTs_Runnable); // should be runnable
-
/* The syscall no is in %eax. For syscalls with <= 6 args,
args 1 .. 6 to the syscall are in %ebx %ecx %edx %esi %edi %ebp.
@@ -5870,12 +5914,8 @@ void VG_(client_syscall) ( ThreadId tid
vg_assert(VG_(is_running_thread)(tid));
+ vg_assert(tst->syscallno == -1);
+ tst->syscallno = syscallno;
- if (syscallno < VGA_(syscall_table_size) &&
- VGA_(syscall_table)[syscallno].before != NULL)
- {
- sys = &VGA_(syscall_table)[syscallno];
- } else {
- sys = &bad_sys;
- }
+ sys = get_syscall_entry(syscallno);
flags = *(sys->flags_ptr);
@@ -5889,5 +5929,5 @@ void VG_(client_syscall) ( ThreadId tid
if (VG_(needs).syscall_wrapper) {
VGP_PUSHCC(VgpSkinSysWrap);
- pre_result = SK_(pre_syscall)(tid, syscallno, mayBlock);
+ tst->tool_pre_syscall_value = SK_(pre_syscall)(tid, syscallno, mayBlock);
VGP_POPCC(VgpSkinSysWrap);
}
@@ -5947,19 +5987,8 @@ void VG_(client_syscall) ( ThreadId tid
SET_SYSCALL_RETVAL(tid, SYSRES);
- if (sys->after != NULL &&
- ((flags & PostOnFail) != 0 || !VG_(is_kerror)(SYSRES)))
- (sys->after)(tst->tid, tst);
-
- /* Do any post-syscall actions
+ VG_(post_syscall)(tid);
- NOTE: this is only called if the syscall completed. If the
- syscall was restarted, then it will call the Tool's
- pre_syscall again, without calling post_syscall (ie, more
- pre's than post's) */
- if (VG_(needs).syscall_wrapper) {
- VGP_PUSHCC(VgpSkinSysWrap);
- SK_(post_syscall)(tid, syscallno, pre_result, SYSRES, /*isBlocking*/True); // did block
- VGP_POPCC(VgpSkinSysWrap);
- }
+ /* VG_(post_syscall) should set this */
+ vg_assert(tst->syscallno == -1);
VGP_POPCC(VgpCoreSysWrap);
--- valgrind/coregrind/x86-linux/syscalls.c #1.15:1.16
@@ -84,12 +84,18 @@ static void restart_syscall(arch_thread_
sigaction says not to), so we only restart if "restart" is True.
- Returns True if the we were somewhere near running a client
- syscall, or False if something else entirely was going on.
+ This will also call VG_(post_syscall)() if the syscall has actually
+ completed (either because it was interrupted, or because it
+ actually finished). It will not call VG_(post_syscall)() if the
+ syscall is set up for restart, which means that the pre-wrapper may
+ get called multiple times.
*/
-Bool VGA_(interrupted_syscall)(arch_thread_t *th_regs,
+void VGA_(interrupted_syscall)(ThreadId tid,
struct vki_ucontext *uc,
Bool restart)
{
- static const Bool debug = False;
+ static const Bool debug = 0;
+
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ arch_thread_t *th_regs = &tst->arch;
Word eip = UCONTEXT_INSTR_PTR(uc);
@@ -100,7 +106,10 @@ Bool VGA_(interrupted_syscall)(arch_thre
if (eip < VGA_(blksys_setup) || eip >= VGA_(blksys_finished)) {
VG_(printf)(" not in syscall (%p - %p)\n", VGA_(blksys_setup), VGA_(blksys_finished));
- return False;
+ vg_assert(tst->syscallno == -1);
+ return;
}
+ vg_assert(tst->syscallno != -1);
+
if (eip >= VGA_(blksys_setup) && eip < VGA_(blksys_restart)) {
/* syscall hasn't even started; go around again */
@@ -114,6 +123,8 @@ Bool VGA_(interrupted_syscall)(arch_thre
if (restart)
restart_syscall(th_regs);
- else
+ else {
PLATFORM_SYSCALL_RET(*th_regs) = -VKI_EINTR;
+ VG_(post_syscall)(tid);
+ }
} else if (eip >= VGA_(blksys_complete) && eip < VGA_(blksys_committed)) {
/* Syscall complete, but result hasn't been written back yet.
@@ -123,4 +134,5 @@ Bool VGA_(interrupted_syscall)(arch_thre
VG_(printf)(" completed: ret=%d\n", UCONTEXT_SYSCALL_RET(uc));
PLATFORM_SYSCALL_RET(*th_regs) = UCONTEXT_SYSCALL_RET(uc);
+ VG_(post_syscall)(tid);
} else if (eip >= VGA_(blksys_committed) && eip < VGA_(blksys_finished)) {
/* Result committed, but the signal mask has not been restored;
@@ -129,7 +141,9 @@ Bool VGA_(interrupted_syscall)(arch_thre
if (debug)
VG_(printf)(" all done\n");
- }
+ VG_(post_syscall)(tid);
+ } else
+ VG_(core_panic)("?? strange syscall interrupt state?");
- return True;
+ tst->syscallno = -1;
}
|