|
@@ -318,17 +318,11 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
|
|
|
}
|
|
|
|
|
|
static inline void __user *
|
|
|
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
|
|
|
+get_sigframe(struct ksignal *ksig, struct pt_regs *regs, int framesize)
|
|
|
{
|
|
|
- unsigned long sp = regs->ARM_sp;
|
|
|
+ unsigned long sp = sigsp(regs->ARM_sp, ksig);
|
|
|
void __user *frame;
|
|
|
|
|
|
- /*
|
|
|
- * This is the X/Open sanctioned signal stack switching.
|
|
|
- */
|
|
|
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
|
|
|
- sp = current->sas_ss_sp + current->sas_ss_size;
|
|
|
-
|
|
|
/*
|
|
|
* ATPCS B01 mandates 8-byte alignment
|
|
|
*/
|
|
@@ -343,11 +337,22 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
|
|
|
return frame;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * translate the signal
|
|
|
+ */
|
|
|
+static inline int map_sig(int sig)
|
|
|
+{
|
|
|
+ struct thread_info *thread = current_thread_info();
|
|
|
+ if (sig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
|
|
|
+ sig = thread->exec_domain->signal_invmap[sig];
|
|
|
+ return sig;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
-setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
|
|
- unsigned long __user *rc, void __user *frame, int usig)
|
|
|
+setup_return(struct pt_regs *regs, struct ksignal *ksig,
|
|
|
+ unsigned long __user *rc, void __user *frame)
|
|
|
{
|
|
|
- unsigned long handler = (unsigned long)ka->sa.sa_handler;
|
|
|
+ unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
|
|
|
unsigned long retcode;
|
|
|
int thumb = 0;
|
|
|
unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
|
|
@@ -357,7 +362,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
|
|
/*
|
|
|
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
|
|
|
*/
|
|
|
- if (ka->sa.sa_flags & SA_THIRTYTWO)
|
|
|
+ if (ksig->ka.sa.sa_flags & SA_THIRTYTWO)
|
|
|
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
|
|
|
|
|
|
#ifdef CONFIG_ARM_THUMB
|
|
@@ -379,12 +384,12 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- if (ka->sa.sa_flags & SA_RESTORER) {
|
|
|
- retcode = (unsigned long)ka->sa.sa_restorer;
|
|
|
+ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
|
|
+ retcode = (unsigned long)ksig->ka.sa.sa_restorer;
|
|
|
} else {
|
|
|
unsigned int idx = thumb << 1;
|
|
|
|
|
|
- if (ka->sa.sa_flags & SA_SIGINFO)
|
|
|
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
|
|
|
idx += 3;
|
|
|
|
|
|
if (__put_user(sigreturn_codes[idx], rc) ||
|
|
@@ -409,7 +414,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- regs->ARM_r0 = usig;
|
|
|
+ regs->ARM_r0 = map_sig(ksig->sig);
|
|
|
regs->ARM_sp = (unsigned long)frame;
|
|
|
regs->ARM_lr = retcode;
|
|
|
regs->ARM_pc = handler;
|
|
@@ -419,9 +424,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
|
|
|
+setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
|
|
{
|
|
|
- struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
|
|
|
+ struct sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
|
|
|
int err = 0;
|
|
|
|
|
|
if (!frame)
|
|
@@ -434,22 +439,21 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
|
|
|
|
|
|
err |= setup_sigframe(frame, regs, set);
|
|
|
if (err == 0)
|
|
|
- err = setup_return(regs, ka, frame->retcode, frame, usig);
|
|
|
+ err = setup_return(regs, ksig, frame->retcode, frame);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
- sigset_t *set, struct pt_regs *regs)
|
|
|
+setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
|
|
{
|
|
|
- struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
|
|
|
+ struct rt_sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
|
|
|
int err = 0;
|
|
|
|
|
|
if (!frame)
|
|
|
return 1;
|
|
|
|
|
|
- err |= copy_siginfo_to_user(&frame->info, info);
|
|
|
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
|
|
|
|
|
|
__put_user_error(0, &frame->sig.uc.uc_flags, err);
|
|
|
__put_user_error(NULL, &frame->sig.uc.uc_link, err);
|
|
@@ -457,7 +461,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
|
|
|
err |= setup_sigframe(&frame->sig, regs, set);
|
|
|
if (err == 0)
|
|
|
- err = setup_return(regs, ka, frame->sig.retcode, frame, usig);
|
|
|
+ err = setup_return(regs, ksig, frame->sig.retcode, frame);
|
|
|
|
|
|
if (err == 0) {
|
|
|
/*
|
|
@@ -475,40 +479,25 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
/*
|
|
|
* OK, we're invoking a handler
|
|
|
*/
|
|
|
-static void
|
|
|
-handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
|
- siginfo_t *info, struct pt_regs *regs)
|
|
|
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
|
|
|
{
|
|
|
- struct thread_info *thread = current_thread_info();
|
|
|
- struct task_struct *tsk = current;
|
|
|
sigset_t *oldset = sigmask_to_save();
|
|
|
- int usig = sig;
|
|
|
int ret;
|
|
|
|
|
|
- /*
|
|
|
- * translate the signal
|
|
|
- */
|
|
|
- if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
|
|
|
- usig = thread->exec_domain->signal_invmap[usig];
|
|
|
-
|
|
|
/*
|
|
|
* Set up the stack frame
|
|
|
*/
|
|
|
- if (ka->sa.sa_flags & SA_SIGINFO)
|
|
|
- ret = setup_rt_frame(usig, ka, info, oldset, regs);
|
|
|
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
|
|
|
+ ret = setup_rt_frame(ksig, oldset, regs);
|
|
|
else
|
|
|
- ret = setup_frame(usig, ka, oldset, regs);
|
|
|
+ ret = setup_frame(ksig, oldset, regs);
|
|
|
|
|
|
/*
|
|
|
* Check that the resulting registers are actually sane.
|
|
|
*/
|
|
|
ret |= !valid_user_regs(regs);
|
|
|
|
|
|
- if (ret != 0) {
|
|
|
- force_sigsegv(sig, tsk);
|
|
|
- return;
|
|
|
- }
|
|
|
- signal_delivered(sig, info, ka, regs, 0);
|
|
|
+ signal_setup_done(ret, ksig, 0);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -523,9 +512,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
|
static int do_signal(struct pt_regs *regs, int syscall)
|
|
|
{
|
|
|
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
|
|
|
- struct k_sigaction ka;
|
|
|
- siginfo_t info;
|
|
|
- int signr;
|
|
|
+ struct ksignal ksig;
|
|
|
int restart = 0;
|
|
|
|
|
|
/*
|
|
@@ -557,33 +544,32 @@ static int do_signal(struct pt_regs *regs, int syscall)
|
|
|
* Get the signal to deliver. When running under ptrace, at this
|
|
|
* point the debugger may change all our registers ...
|
|
|
*/
|
|
|
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
|
/*
|
|
|
* Depending on the signal settings we may need to revert the
|
|
|
* decision to restart the system call. But skip this if a
|
|
|
* debugger has chosen to restart at a different PC.
|
|
|
*/
|
|
|
- if (regs->ARM_pc != restart_addr)
|
|
|
- restart = 0;
|
|
|
- if (signr > 0) {
|
|
|
- if (unlikely(restart)) {
|
|
|
+ if (get_signal(&ksig)) {
|
|
|
+ /* handler */
|
|
|
+ if (unlikely(restart) && regs->ARM_pc == restart_addr) {
|
|
|
if (retval == -ERESTARTNOHAND ||
|
|
|
retval == -ERESTART_RESTARTBLOCK
|
|
|
|| (retval == -ERESTARTSYS
|
|
|
- && !(ka.sa.sa_flags & SA_RESTART))) {
|
|
|
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
|
|
|
regs->ARM_r0 = -EINTR;
|
|
|
regs->ARM_pc = continue_addr;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- handle_signal(signr, &ka, &info, regs);
|
|
|
- return 0;
|
|
|
+ handle_signal(&ksig, regs);
|
|
|
+ } else {
|
|
|
+ /* no handler */
|
|
|
+ restore_saved_sigmask();
|
|
|
+ if (unlikely(restart) && regs->ARM_pc == restart_addr) {
|
|
|
+ regs->ARM_pc = continue_addr;
|
|
|
+ return restart;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- restore_saved_sigmask();
|
|
|
- if (unlikely(restart))
|
|
|
- regs->ARM_pc = continue_addr;
|
|
|
- return restart;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
asmlinkage int
|