Re: [Qemu-devel] [PATCH] linux-user sigaltstack() syscall

2007-09-25 Thread Thayne Harbaugh
On Mon, 2007-09-24 at 23:04 -0600, Thayne Harbaugh wrote:
 This patch adds the sigaltstack() syscall for linux-user.

The previous patch relied on the EFAULT patch, this newer version does
not.  It also fixes a few places that used tswap32() that should use
__put_user().
Index: qemu/linux-user/signal.c
===
--- qemu.orig/linux-user/signal.c	2007-09-25 05:46:34.0 -0600
+++ qemu/linux-user/signal.c	2007-09-25 06:35:23.0 -0600
@@ -26,6 +26,7 @@
 #include errno.h
 #include sys/ucontext.h
 
+#include target_signal.h
 #include qemu.h
 
 //#define DEBUG_SIGNAL
@@ -45,6 +46,12 @@
  first signal, we put it here */
 };
 
+struct target_sigaltstack target_sigaltstack_used = {
+.ss_sp = 0,
+.ss_size = 0,
+.ss_flags = TARGET_SS_DISABLE,
+};
+
 static struct emulated_sigaction sigact_table[TARGET_NSIG];
 static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
 static struct sigqueue *first_free; /* first free siginfo queue entry */
@@ -92,6 +99,18 @@
 };
 static uint8_t target_to_host_signal_table[65];
 
+static inline int on_sig_stack(unsigned long sp)
+{
+return (sp - target_sigaltstack_used.ss_sp
+ target_sigaltstack_used.ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
+: on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
 static inline int host_to_target_signal(int sig)
 {
 return host_to_target_signal_table[sig];
@@ -419,6 +438,67 @@
 }
 }
 
+int do_sigaltstack(const struct target_sigaltstack *uss,
+   struct target_sigaltstack *uoss,
+   target_ulong sp)
+{
+int ret;
+struct target_sigaltstack oss;
+
+/* XXX: test errors */
+if(uoss)
+{
+__put_user(target_sigaltstack_used.ss_sp, oss.ss_sp);
+__put_user(target_sigaltstack_used.ss_size, oss.ss_size);
+__put_user(sas_ss_flags(sp), oss.ss_flags);
+}
+
+if(uss)
+{
+	struct target_sigaltstack ss;
+
+	ret = -EFAULT;
+	if (!access_ok(VERIFY_READ, uss, sizeof(*uss))
+	|| __get_user(ss.ss_sp, uss-ss_sp)
+	|| __get_user(ss.ss_size, uss-ss_size)
+	|| __get_user(ss.ss_flags, uss-ss_flags))
+goto out;
+
+	ret = -EPERM;
+	if (on_sig_stack(sp))
+goto out;
+
+	ret = -EINVAL;
+	if (ss.ss_flags != TARGET_SS_DISABLE
+ ss.ss_flags != TARGET_SS_ONSTACK
+ ss.ss_flags != 0)
+goto out;
+
+	if (ss.ss_flags == TARGET_SS_DISABLE) {
+ss.ss_size = 0;
+ss.ss_sp = 0;
+	} else {
+ret = -ENOMEM;
+if (ss.ss_size  MINSIGSTKSZ)
+goto out;
+	}
+
+target_sigaltstack_used.ss_sp = ss.ss_sp;
+target_sigaltstack_used.ss_size = ss.ss_size;
+}
+
+if (uoss) {
+ret = -EFAULT;
+if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss)))
+goto out;
+memcpy(uoss, oss, sizeof(oss));
+}
+
+ret = 0;
+out:
+return ret;
+}
+
 int do_sigaction(int sig, const struct target_sigaction *act,
  struct target_sigaction *oact)
 {
@@ -551,12 +631,6 @@
 	target_ulong cr2;
 };
 
-typedef struct target_sigaltstack {
-	target_ulong ss_sp;
-	int ss_flags;
-	target_ulong ss_size;
-} target_stack_t;
-
 struct target_ucontext {
 target_ulong	  tuc_flags;
 	target_ulong  tuc_link;
@@ -640,16 +714,14 @@
 
 	/* Default to using normal stack */
 	esp = env-regs[R_ESP];
-#if 0
 	/* This is the X/Open sanctioned signal stack switching.  */
-	if (ka-sa.sa_flags  SA_ONSTACK) {
-		if (sas_ss_flags(esp) == 0)
-			esp = current-sas_ss_sp + current-sas_ss_size;
-	}
+if (ka-sa.sa_flags  TARGET_SA_ONSTACK) {
+if (sas_ss_flags(esp) == 0)
+esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+}
 
 	/* This is the legacy signal stack switching. */
 	else
-#endif
 if ((env-segs[R_SS].selector  0x) != __USER_DS 
 !(ka-sa.sa_flags  TARGET_SA_RESTORER) 
 ka-sa.sa_restorer) {
@@ -750,11 +822,11 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, frame-uc.tuc_flags);
 	err |= __put_user(0, frame-uc.tuc_link);
-	err |= __put_user(/*current-sas_ss_sp*/ 0,
+	err |= __put_user(target_sigaltstack_used.ss_sp,
 			  frame-uc.tuc_stack.ss_sp);
-	err |= __put_user(/* sas_ss_flags(regs-esp) */ 0,
+	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
 			  frame-uc.tuc_stack.ss_flags);
-	err |= __put_user(/* current-sas_ss_size */ 0,
+	err |= __put_user(target_sigaltstack_used.ss_size,
 			  frame-uc.tuc_stack.ss_size);
 	err |= setup_sigcontext(frame-uc.tuc_mcontext, frame-fpstate,
 			env, set-sig[0]);
@@ -880,7 +952,6 @@
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env-regs[R_ESP] - 4);
 sigset_t set;
-//	stack_t st;
 	int eax;
 
 #if 0
@@ -893,13 +964,9 @@
 	if 

[Qemu-devel] [PATCH] linux-user sigaltstack() syscall

2007-09-24 Thread Thayne Harbaugh
This patch adds the sigaltstack() syscall for linux-user.
Index: qemu/linux-user/signal.c
===
--- qemu.orig/linux-user/signal.c	2007-09-24 22:45:48.0 -0600
+++ qemu/linux-user/signal.c	2007-09-24 22:56:18.0 -0600
@@ -26,6 +26,7 @@
 #include errno.h
 #include sys/ucontext.h
 
+#include target_signal.h
 #include qemu.h
 
 /*
@@ -51,6 +52,12 @@
  first signal, we put it here */
 };
 
+struct target_sigaltstack target_sigaltstack_used = {
+.ss_sp = 0,
+.ss_size = 0,
+.ss_flags = TARGET_SS_DISABLE,
+};
+
 static struct emulated_sigaction sigact_table[TARGET_NSIG];
 static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
 static struct sigqueue *first_free; /* first free siginfo queue entry */
@@ -98,6 +105,18 @@
 };
 static uint8_t target_to_host_signal_table[65];
 
+static inline int on_sig_stack(unsigned long sp)
+{
+return (sp - target_sigaltstack_used.ss_sp
+ target_sigaltstack_used.ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
+: on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
 static inline int host_to_target_signal(int sig)
 {
 return host_to_target_signal_table[sig];
@@ -420,6 +439,66 @@
 }
 }
 
+int do_sigaltstack(const struct target_sigaltstack *uss,
+   struct target_sigaltstack *uoss,
+   target_ulong sp)
+{
+int ret;
+struct target_sigaltstack oss;
+
+/* XXX: test errors */
+if(uoss)
+{
+oss.ss_sp = tswap32(target_sigaltstack_used.ss_sp);
+oss.ss_size = tswap32(target_sigaltstack_used.ss_size);
+oss.ss_flags = tswap32(sas_ss_flags(sp));
+}
+
+if(uss)
+{
+	struct target_sigaltstack ss;
+
+	ret = -EFAULT;
+	if (!access_ok(VERIFY_READ, uss, sizeof(*uss))
+	|| __get_user(ss.ss_sp, uss-ss_sp)
+	|| __get_user(ss.ss_size, uss-ss_size)
+	|| __get_user(ss.ss_flags, uss-ss_flags))
+goto out;
+
+	ret = -EPERM;
+	if (on_sig_stack(sp))
+goto out;
+
+	ret = -EINVAL;
+	if (ss.ss_flags != TARGET_SS_DISABLE
+ ss.ss_flags != TARGET_SS_ONSTACK
+ ss.ss_flags != 0)
+goto out;
+
+	if (ss.ss_flags == TARGET_SS_DISABLE) {
+ss.ss_size = 0;
+ss.ss_sp = 0;
+	} else {
+ret = -ENOMEM;
+if (ss.ss_size  MINSIGSTKSZ)
+goto out;
+	}
+
+target_sigaltstack_used.ss_sp = ss.ss_sp;
+target_sigaltstack_used.ss_size = ss.ss_size;
+}
+
+if (uoss) {
+ret = -EFAULT;
+if (copy_to_user(uoss, oss, sizeof(oss)))
+goto out;
+}
+
+ret = 0;
+out:
+return ret;
+}
+
 int do_sigaction(int sig, const struct target_sigaction *act,
  struct target_sigaction *oact)
 {
@@ -550,12 +629,6 @@
 	target_ulong cr2;
 };
 
-typedef struct target_sigaltstack {
-	target_ulong ss_sp;
-	int ss_flags;
-	target_ulong ss_size;
-} target_stack_t;
-
 struct target_ucontext {
 target_ulong	  tuc_flags;
 	target_ulong  tuc_link;
@@ -639,16 +712,14 @@
 
 	/* Default to using normal stack */
 	esp = env-regs[R_ESP];
-#if 0
 	/* This is the X/Open sanctioned signal stack switching.  */
-	if (ka-sa.sa_flags  SA_ONSTACK) {
-		if (sas_ss_flags(esp) == 0)
-			esp = current-sas_ss_sp + current-sas_ss_size;
-	}
+if (ka-sa.sa_flags  TARGET_SA_ONSTACK) {
+if (sas_ss_flags(esp) == 0)
+esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+}
 
 	/* This is the legacy signal stack switching. */
 	else
-#endif
 if ((env-segs[R_SS].selector  0x) != __USER_DS 
 !(ka-sa.sa_flags  TARGET_SA_RESTORER) 
 ka-sa.sa_restorer) {
@@ -749,11 +820,11 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, frame-uc.tuc_flags);
 	err |= __put_user(0, frame-uc.tuc_link);
-	err |= __put_user(/*current-sas_ss_sp*/ 0,
+	err |= __put_user(target_sigaltstack_used.ss_sp,
 			  frame-uc.tuc_stack.ss_sp);
-	err |= __put_user(/* sas_ss_flags(regs-esp) */ 0,
+	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
 			  frame-uc.tuc_stack.ss_flags);
-	err |= __put_user(/* current-sas_ss_size */ 0,
+	err |= __put_user(target_sigaltstack_used.ss_size,
 			  frame-uc.tuc_stack.ss_size);
 	err |= setup_sigcontext(frame-uc.tuc_mcontext, frame-fpstate,
 			env, set-sig[0]);
@@ -877,7 +948,6 @@
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env-regs[R_ESP] - 4);
 sigset_t set;
-//	stack_t st;
 	int eax;
 
 #if 0
@@ -890,13 +960,9 @@
 	if (restore_sigcontext(env, frame-uc.tuc_mcontext, eax))
 		goto badframe;
 
-#if 0
-	if (__copy_from_user(st, frame-uc.tuc_stack, sizeof(st)))
+	if (do_sigaltstack(frame-uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT)
 		goto badframe;
-	/* It is more difficult to avoid calling this