summary refs log tree commit diff
path: root/arch/um/sys-i386
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/sys-i386')
-rw-r--r--arch/um/sys-i386/ptrace.c15
-rw-r--r--arch/um/sys-i386/signal.c59
-rw-r--r--arch/um/sys-i386/user-offsets.c10
3 files changed, 64 insertions, 20 deletions
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index e839ce65ad28..8032a105949a 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -6,6 +6,7 @@
 #include <linux/config.h>
 #include <linux/compiler.h>
 #include "linux/sched.h"
+#include "linux/mm.h"
 #include "asm/elf.h"
 #include "asm/ptrace.h"
 #include "asm/uaccess.h"
@@ -26,9 +27,17 @@ int is_syscall(unsigned long addr)
 
 	n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
 	if(n){
-		printk("is_syscall : failed to read instruction from 0x%lx\n",
-		       addr);
-		return(0);
+		/* access_process_vm() grants access to vsyscall and stub,
+		 * while copy_from_user doesn't. Maybe access_process_vm is
+		 * slow, but that doesn't matter, since it will be called only
+		 * in case of singlestepping, if copy_from_user failed.
+		 */
+		n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
+		if(n != sizeof(instr)) {
+			printk("is_syscall : failed to read instruction from "
+			       "0x%lx\n", addr);
+			return(1);
+		}
 	}
 	/* int 0x80 or sysenter */
 	return((instr == 0x80cd) || (instr == 0x340f));
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 7cd1a82dc8c2..33a40f5ef0d2 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -58,7 +58,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
 }
 
 int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
-                         struct pt_regs *regs)
+                         struct pt_regs *regs, unsigned long sp)
 {
   	struct sigcontext sc;
 	unsigned long fpregs[HOST_FP_SIZE];
@@ -72,7 +72,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
 	sc.edi = REGS_EDI(regs->regs.skas.regs);
 	sc.esi = REGS_ESI(regs->regs.skas.regs);
 	sc.ebp = REGS_EBP(regs->regs.skas.regs);
-	sc.esp = REGS_SP(regs->regs.skas.regs);
+	sc.esp = sp;
 	sc.ebx = REGS_EBX(regs->regs.skas.regs);
 	sc.edx = REGS_EDX(regs->regs.skas.regs);
 	sc.ecx = REGS_ECX(regs->regs.skas.regs);
@@ -132,7 +132,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
 }
 
 int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
-		       struct sigcontext *from, int fpsize)
+		       struct sigcontext *from, int fpsize, unsigned long sp)
 {
 	struct _fpstate *to_fp, *from_fp;
 	int err;
@@ -140,11 +140,18 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
 	to_fp =	(fp ? fp : (struct _fpstate *) (to + 1));
 	from_fp = from->fpstate;
 	err = copy_to_user(to, from, sizeof(*to));
+
+	/* The SP in the sigcontext is the updated one for the signal
+	 * delivery.  The sp passed in is the original, and this needs
+	 * to be restored, so we stick it in separately.
+	 */
+	err |= copy_to_user(&SC_SP(to), sp, sizeof(sp));
+
 	if(from_fp != NULL){
 		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
 		err |= copy_to_user(to_fp, from_fp, fpsize);
 	}
-	return(err);
+	return err;
 }
 #endif
 
@@ -159,11 +166,11 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from)
 }
 
 static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
-			   struct pt_regs *from)
+			   struct pt_regs *from, unsigned long sp)
 {
 	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
-					      sizeof(*fp)),
-                           copy_sc_to_user_skas(to, fp, from)));
+					      sizeof(*fp), sp),
+                           copy_sc_to_user_skas(to, fp, from, sp)));
 }
 
 static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
@@ -174,7 +181,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
 	err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
 	err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
 	err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
-	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs);
+	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
 	err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
 	return(err);
 }
@@ -207,6 +214,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 {
 	struct sigframe __user *frame;
 	void *restorer;
+	unsigned long save_sp = PT_REGS_SP(regs);
 	int err = 0;
 
 	stack_top &= -8UL;
@@ -218,9 +226,19 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
+	/* Update SP now because the page fault handler refuses to extend
+	 * the stack if the faulting address is too far below the current
+	 * SP, which frame now certainly is.  If there's an error, the original
+	 * value is restored on the way out.
+	 * When writing the sigcontext to the stack, we have to write the
+	 * original value, so that's passed to copy_sc_to_user, which does
+	 * the right thing with it.
+	 */
+	PT_REGS_SP(regs) = (unsigned long) frame;
+
 	err |= __put_user(restorer, &frame->pretcode);
 	err |= __put_user(sig, &frame->sig);
-	err |= copy_sc_to_user(&frame->sc, NULL, regs);
+	err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp);
 	err |= __put_user(mask->sig[0], &frame->sc.oldmask);
 	if (_NSIG_WORDS > 1)
 		err |= __copy_to_user(&frame->extramask, &mask->sig[1],
@@ -238,7 +256,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
 	if(err)
-		return(err);
+		goto err;
 
 	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
@@ -248,7 +266,11 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
-	return(0);
+	return 0;
+
+err:
+	PT_REGS_SP(regs) = save_sp;
+	return err;
 }
 
 int setup_signal_stack_si(unsigned long stack_top, int sig,
@@ -257,6 +279,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 {
 	struct rt_sigframe __user *frame;
 	void *restorer;
+	unsigned long save_sp = PT_REGS_SP(regs);
 	int err = 0;
 
 	stack_top &= -8UL;
@@ -268,13 +291,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
+	/* See comment above about why this is here */
+	PT_REGS_SP(regs) = (unsigned long) frame;
+
 	err |= __put_user(restorer, &frame->pretcode);
 	err |= __put_user(sig, &frame->sig);
 	err |= __put_user(&frame->info, &frame->pinfo);
 	err |= __put_user(&frame->uc, &frame->puc);
 	err |= copy_siginfo_to_user(&frame->info, info);
 	err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
-				     PT_REGS_SP(regs));
+				     save_sp);
 
 	/*
 	 * This is movl $,%eax ; int $0x80
@@ -288,9 +314,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 	err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
 	if(err)
-		return(err);
+		goto err;
 
-	PT_REGS_SP(regs) = (unsigned long) frame;
 	PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
 	PT_REGS_EAX(regs) = (unsigned long) sig;
 	PT_REGS_EDX(regs) = (unsigned long) &frame->info;
@@ -298,7 +323,11 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 
 	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
 		ptrace_notify(SIGTRAP);
-	return(0);
+	return 0;
+
+err:
+	PT_REGS_SP(regs) = save_sp;
+	return err;
 }
 
 long sys_sigreturn(struct pt_regs regs)
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
index 26b68675053d..6f4ef2b7fa4a 100644
--- a/arch/um/sys-i386/user-offsets.c
+++ b/arch/um/sys-i386/user-offsets.c
@@ -3,12 +3,13 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <linux/stddef.h>
+#include <sys/poll.h>
 
 #define DEFINE(sym, val) \
-        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
 #define DEFINE_LONGS(sym, val) \
-        asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long)))
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long)))
 
 #define OFFSET(sym, str, mem) \
 	DEFINE(sym, offsetof(struct str, mem));
@@ -67,4 +68,9 @@ void foo(void)
 	DEFINE(HOST_ES, ES);
 	DEFINE(HOST_GS, GS);
 	DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct));
+
+	/* XXX Duplicated between i386 and x86_64 */
+	DEFINE(UM_POLLIN, POLLIN);
+	DEFINE(UM_POLLPRI, POLLPRI);
+	DEFINE(UM_POLLOUT, POLLOUT);
 }