summaryrefslogtreecommitdiff
path: root/arch/um/include/sysdep-i386/ptrace_user.h
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2008-02-24 02:23:49 +0300
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-24 04:12:15 +0300
commit2f56debd77a8f52f1ac1d3c3d89cc7ce5e083230 (patch)
tree353847d10aa0d5bc1de2707ecd8fa2391ad096f3 /arch/um/include/sysdep-i386/ptrace_user.h
parente4d06b3f904ddfab4531a1e23f1f5e1bd284b605 (diff)
downloadlinux-2f56debd77a8f52f1ac1d3c3d89cc7ce5e083230.tar.xz
uml: fix FP register corruption
Commit ee3d9bd4de1ed93d2a7ee41c331ed30a1c7b8acd ("uml: simplify SIGSEGV handling"), while greatly simplifying the kernel SIGSEGV handler that runs in the process address space, introduced a bug which corrupts FP state in the process. Previously, the SIGSEGV handler called the sigreturn system call by hand - it couldn't return through the restorer provided to it because that could try to call the libc restorer which likely wouldn't exist in the process address space. So, it blocked off some signals, including SIGUSR1, on entry to the SIGSEGV handler, queued a SIGUSR1 to itself, and invoked sigreturn. The SIGUSR1 was delivered, and was visible to the UML kernel after sigreturn finished. The commit eliminated the signal masking and the call to sigreturn. The handler simply hits itself with a SIGTRAP to let the UML kernel know that it is finished. UML then restores the process registers, which effectively longjmps the process out of the signal handler, skipping sigreturn's restoring of register state and the signal mask. The bug is that the host apparently sets used_fp to 0 when it saves the process FP state in the sigcontext on the process signal stack. Thus, when the process is longjmped out of the handler, its FP state is corrupt because it wasn't saved on the context switch to the UML kernel. This manifested itself as sleep hanging. For some reason, sleep uses floating point in order to calculate the sleep interval. When a page fault corrupts its FP state, it is faked into essentially sleeping forever. This patch saves the FP state before entering the SIGSEGV handler and restores it afterwards. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/include/sysdep-i386/ptrace_user.h')
-rw-r--r--arch/um/include/sysdep-i386/ptrace_user.h3
1 files changed, 3 insertions, 0 deletions
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index 899aa4b2a78d..75650723c38f 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -9,6 +9,7 @@
#include <sys/ptrace.h>
#include <linux/ptrace.h>
#include <asm/ptrace.h>
+#include "user_constants.h"
#define PT_OFFSET(r) ((r) * sizeof(long))
@@ -40,6 +41,8 @@
#define PT_SP_OFFSET PT_OFFSET(UESP)
#define PT_SP(regs) ((regs)[UESP])
+#define FP_SIZE ((HOST_XFP_SIZE > HOST_FP_SIZE) ? HOST_XFP_SIZE : HOST_FP_SIZE)
+
#ifndef FRAME_SIZE
#define FRAME_SIZE (17)
#endif