コード例 #1
0
ファイル: signal.c プロジェクト: BackupTheBerlios/tuxap
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 *
 * "r0" and "r19" are the registers we need to restore for system call
 * restart. "r0" is also used as an indicator whether we can restart at
 * all (if we get here from anything but a syscall return, it will be 0)
 */
static int
do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
	  unsigned long r0, unsigned long r19)
{
	siginfo_t info;
	int signr;
	unsigned long single_stepping = ptrace_cancel_bpt(current);
	struct k_sigaction ka;

	if (!oldset)
		oldset = &current->blocked;

	/* This lets the debugger run, ... */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	/* ... so re-check the single stepping. */
	single_stepping |= ptrace_cancel_bpt(current);

	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
		if (r0) syscall_restart(r0, r19, regs, &ka);
		handle_signal(signr, &ka, &info, oldset, regs, sw);
		if (single_stepping) 
			ptrace_set_bpt(current); /* re-set bpt */
		return 1;
	}

	if (r0) {
	  	switch (regs->r0) {
		case ERESTARTNOHAND:
		case ERESTARTSYS:
		case ERESTARTNOINTR:
			/* Reset v0 and a3 and replay syscall.  */
			regs->r0 = r0;
			regs->r19 = r19;
			regs->pc -= 4;
			break;
		case ERESTART_RESTARTBLOCK:
			/* Force v0 to the restart syscall and reply.  */
			regs->r0 = __NR_restart_syscall;
			regs->pc -= 4;
			break;
		}
	}
	if (single_stepping)
		ptrace_set_bpt(current);	/* re-set breakpoint */

	return 0;
}
コード例 #2
0
ファイル: signal.c プロジェクト: dot-Sean/linux_kernels
asmlinkage void
do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
             struct switch_stack *sw)
{
    sigset_t set;

    /* Verify that it's a good sigcontext before using it */
    if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
        goto give_sigsegv;
    if (__get_user(set.sig[0], &frame->sc.sc_mask)
            || (_NSIG_WORDS > 1
                && __copy_from_user(&set.sig[1], &frame->extramask,
                                    sizeof(frame->extramask))))
        goto give_sigsegv;

    sigdelsetmask(&set, ~_BLOCKABLE);
    spin_lock_irq(&current->sigmask_lock);
    current->blocked = set;
    recalc_sigpending(current);
    spin_unlock_irq(&current->sigmask_lock);

    if (restore_sigcontext(&frame->sc, regs, sw))
        goto give_sigsegv;

    /* Send SIGTRAP if we're single-stepping: */
    if (ptrace_cancel_bpt (current))
        send_sig(SIGTRAP, current, 1);
    return;

give_sigsegv:
    force_sig(SIGSEGV, current);
}
コード例 #3
0
ファイル: signal.c プロジェクト: gtvhacker/Logitech-Revue
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
	struct sigframe __user *frame;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

	/*
	 * Since we stacked the signal on a 64-bit boundary,
	 * then 'sp' should be word aligned here.  If it's
	 * not, then the user is trying to mess with us.
	 */
	if (regs->ARM_sp & 7)
		goto badframe;

	frame = (struct sigframe __user *)regs->ARM_sp;

	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
		goto badframe;

	if (restore_sigframe(regs, frame))
		goto badframe;

	/* Send SIGTRAP if we're single-stepping */
	if (current->ptrace & PT_SINGLESTEP) {
		ptrace_cancel_bpt(current);
		send_sig(SIGTRAP, current, 1);
	}

	return regs->ARM_r0;

badframe:
	force_sig(SIGSEGV, current);
	return 0;
}
コード例 #4
0
ファイル: signal.c プロジェクト: 22101959/linux-3.8.13
asmlinkage void
do_rt_sigreturn(struct rt_sigframe __user *frame)
{
	struct pt_regs *regs = current_pt_regs();
	sigset_t set;

	/* Verify that it's a good ucontext_t before using it */
	if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
		goto give_sigsegv;
	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto give_sigsegv;

	set_current_blocked(&set);

	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
		goto give_sigsegv;

	/* Send SIGTRAP if we're single-stepping: */
	if (ptrace_cancel_bpt (current)) {
		siginfo_t info;

		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
	}
	return;

give_sigsegv:
	force_sig(SIGSEGV, current);
}
コード例 #5
0
ファイル: signal.c プロジェクト: 22101959/linux-3.8.13
asmlinkage void
do_sigreturn(struct sigcontext __user *sc)
{
	struct pt_regs *regs = current_pt_regs();
	sigset_t set;

	/* Verify that it's a good sigcontext before using it */
	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
		goto give_sigsegv;
	if (__get_user(set.sig[0], &sc->sc_mask))
		goto give_sigsegv;

	set_current_blocked(&set);

	if (restore_sigcontext(sc, regs))
		goto give_sigsegv;

	/* Send SIGTRAP if we're single-stepping: */
	if (ptrace_cancel_bpt (current)) {
		siginfo_t info;

		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
	}
	return;

give_sigsegv:
	force_sig(SIGSEGV, current);
}
コード例 #6
0
ファイル: signal.c プロジェクト: 22101959/linux-3.8.13
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 *
 * "r0" and "r19" are the registers we need to restore for system call
 * restart. "r0" is also used as an indicator whether we can restart at
 * all (if we get here from anything but a syscall return, it will be 0)
 */
static void
do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
{
	siginfo_t info;
	int signr;
	unsigned long single_stepping = ptrace_cancel_bpt(current);
	struct k_sigaction ka;

	/* This lets the debugger run, ... */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);

	/* ... so re-check the single stepping. */
	single_stepping |= ptrace_cancel_bpt(current);

	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
		if (r0)
			syscall_restart(r0, r19, regs, &ka);
		handle_signal(signr, &ka, &info, regs);
		if (single_stepping) 
			ptrace_set_bpt(current); /* re-set bpt */
		return;
	}

	if (r0) {
	  	switch (regs->r0) {
		case ERESTARTNOHAND:
		case ERESTARTSYS:
		case ERESTARTNOINTR:
			/* Reset v0 and a3 and replay syscall.  */
			regs->r0 = r0;
			regs->r19 = r19;
			regs->pc -= 4;
			break;
		case ERESTART_RESTARTBLOCK:
			/* Force v0 to the restart syscall and reply.  */
			regs->r0 = __NR_restart_syscall;
			regs->pc -= 4;
			break;
		}
	}

	/* If there's no signal to deliver, we just restore the saved mask.  */
	restore_saved_sigmask();
	if (single_stepping)
		ptrace_set_bpt(current);	/* re-set breakpoint */
}
コード例 #7
0
asmlinkage int
sys_rt_sigreturn(unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,
                 unsigned long arg5,unsigned long arg6,unsigned long history)
{
    struct rt_sigframe __user* frame;
    sigset_t set;
    struct pt_regs* regs=(struct pt_regs*)&history;

    current_thread_info()->restart_block.fn= do_no_restart_syscall;

    if(regs->sp&4) {
        goto badframe;
    }

    frame=(struct rt_sigframe __user*)regs->sp;

    if(!access_ok(VERIFY_READ,frame,sizeof(*frame))) {
        goto badframe;
    }
    if(__copy_from_user(&set,&frame->uc.uc_sigmask,sizeof(set))) {
        goto badframe;
    }

    sigdelsetmask(&set,~_BLOCKABLE);
    spin_lock_irq(&current->sighand->siglock);
    current->blocked=set;
    recalc_sigpending();
    spin_unlock_irq(&current->sighand->siglock);

    if(restore_sigcontext(regs,&frame->uc.uc_mcontext)) {
        goto badframe;
    }

    if(do_sigaltstack(&frame->uc.uc_stack,NULL,regs->sp) == EFAULT) {
        goto badframe;
    }

    /*
     *FIXME:  I don't know how to trace TriMedia executable.
     */
#if 0
    if(current->ptrace & PT_SINGLESTEP) {
        ptrace_cancel_bpt(current);
        send_sig(SIGTRAP,current,1);
    }
#endif

    return regs->r5;

badframe:
    force_sig(SIGSEGV,current);
    return 0;
}
コード例 #8
0
asmlinkage int
sys_sigreturn(unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,
              unsigned long arg5,unsigned long arg6,unsigned long history)
{
    struct sigframe __user *frame;
    sigset_t set;
    struct pt_regs* regs=(struct pt_regs*)&history;

    current_thread_info()->restart_block.fn=do_no_restart_syscall;

    if(regs->sp&4) {
        goto badframe;
    }

    frame=(struct sigframe __user*)regs->sp;

    if(!access_ok(VERIFY_READ,frame,sizeof(*frame))) {
        goto badframe;
    }

    if (__get_user(set.sig[0], &frame->sc.oldmask)
            || (_NSIG_WORDS > 1
                && __copy_from_user(&set.sig[1], &frame->extramask,
                                    sizeof(frame->extramask))))
        goto badframe;

    sigdelsetmask(&set,~_BLOCKABLE);
    spin_lock_irq(&current->sighand->siglock);
    current->blocked=set;
    recalc_sigpending();
    spin_unlock_irq(&current->sighand->siglock);

    if(restore_sigcontext(regs,&frame->sc)) {
        goto badframe;
    }

    /*
     *FIXME: I don't know how to trace TriMedia executable.
     */
#if 0
    /* Send SIGTRAP if we're single-stepping */
    if (current->ptrace & PT_SINGLESTEP) {
        ptrace_cancel_bpt(current);
        send_sig(SIGTRAP, current, 1);
    }
#endif

    return regs->r5;

badframe:
    force_sig(SIGSEGV,current);
    return 0;
}
コード例 #9
0
ファイル: signal.c プロジェクト: iPodLinux/linux-2.6.7-ipod
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
    struct rt_sigframe __user *frame;
    sigset_t set;

    /* Always make any pending restarted system calls return -EINTR */
    current_thread_info()->restart_block.fn = do_no_restart_syscall;

    /*
     * Since we stacked the signal on a 64-bit boundary,
     * then 'sp' should be word aligned here.  If it's
     * not, then the user is trying to mess with us.
     */
    if (regs->ARM_sp & 7)
        goto badframe;

    frame = (struct rt_sigframe __user *)regs->ARM_sp;

    if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
        goto badframe;
    if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
        goto badframe;

    sigdelsetmask(&set, ~_BLOCKABLE);
    spin_lock_irq(&current->sighand->siglock);
    current->blocked = set;
    recalc_sigpending();
    spin_unlock_irq(&current->sighand->siglock);

    if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
        goto badframe;

    if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
        goto badframe;

    /* Send SIGTRAP if we're single-stepping */
    if (current->ptrace & PT_SINGLESTEP) {
        ptrace_cancel_bpt(current);
        send_sig(SIGTRAP, current, 1);
    }

    return regs->ARM_r0;

badframe:
    force_sig(SIGSEGV, current);
    return 0;
}
コード例 #10
0
ファイル: signal.c プロジェクト: dmgerman/linux-pre-history
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
	struct sigframe *frame;
	sigset_t set;

	/*
	 * Since we stacked the signal on a word boundary,
	 * then 'sp' should be word aligned here.  If it's
	 * not, then the user is trying to mess with us.
	 */
	if (regs->ARM_sp & 3)
		goto badframe;

	frame = (struct sigframe *)regs->ARM_sp;

	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
		goto badframe;
	if (__get_user(set.sig[0], &frame->sc.oldmask)
	    || (_NSIG_WORDS > 1
	        && __copy_from_user(&set.sig[1], &frame->extramask,
				    sizeof(frame->extramask))))
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
	spin_lock_irq(&current->sigmask_lock);
	current->blocked = set;
	recalc_sigpending(current);
	spin_unlock_irq(&current->sigmask_lock);

	if (restore_sigcontext(regs, &frame->sc))
		goto badframe;

	/* Send SIGTRAP if we're single-stepping */
	if (ptrace_cancel_bpt(current))
		send_sig(SIGTRAP, current, 1);

	return regs->ARM_r0;

badframe:
	force_sig(SIGSEGV, current);
	return 0;
}
コード例 #11
0
asmlinkage void
do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs,
	     struct switch_stack *sw)
{
	sigset_t set;

	/* Verify that it's a good sigcontext before using it */
	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
		goto give_sigsegv;
	if (__get_user(set.sig[0], &sc->sc_mask))
		goto give_sigsegv;

	sigdelsetmask(&set, ~_BLOCKABLE);
	spin_lock_irq(&current->sighand->siglock);
	current->blocked = set;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	if (restore_sigcontext(sc, regs, sw))
		goto give_sigsegv;

	/* Send SIGTRAP if we're single-stepping: */
	if (ptrace_cancel_bpt (current)) {
		siginfo_t info;

		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
	}
	return;

give_sigsegv:
	force_sig(SIGSEGV, current);
}
コード例 #12
0
ファイル: signal.c プロジェクト: BackupTheBerlios/tuxap
asmlinkage void
do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs,
		struct switch_stack *sw)
{
	sigset_t set;

	/* Verify that it's a good ucontext_t before using it */
	if (verify_area(VERIFY_READ, &frame->uc, sizeof(frame->uc)))
		goto give_sigsegv;
	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto give_sigsegv;

	sigdelsetmask(&set, ~_BLOCKABLE);
	spin_lock_irq(&current->sighand->siglock);
	current->blocked = set;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
		goto give_sigsegv;

	/* Send SIGTRAP if we're single-stepping: */
	if (ptrace_cancel_bpt (current)) {
		siginfo_t info;

		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
	}
	return;

give_sigsegv:
	force_sig(SIGSEGV, current);
}
コード例 #13
0
ファイル: signal.c プロジェクト: dot-Sean/linux_kernels
asmlinkage void
do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
                struct switch_stack *sw)
{
    sigset_t set;
    stack_t st;

    /* Verify that it's a good sigcontext before using it */
    if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
        goto give_sigsegv;
    if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
        goto give_sigsegv;

    sigdelsetmask(&set, ~_BLOCKABLE);
    spin_lock_irq(&current->sigmask_lock);
    current->blocked = set;
    recalc_sigpending(current);
    spin_unlock_irq(&current->sigmask_lock);

    if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
        goto give_sigsegv;

    if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
        goto give_sigsegv;
    /* It is more difficult to avoid calling this function than to
       call it and ignore errors.  */
    do_sigaltstack(&st, NULL, rdusp());

    /* Send SIGTRAP if we're single-stepping: */
    if (ptrace_cancel_bpt (current))
        send_sig(SIGTRAP, current, 1);
    return;

give_sigsegv:
    force_sig(SIGSEGV, current);
}
コード例 #14
0
asmlinkage void
do_entIF(unsigned long type, struct pt_regs *regs)
{
	siginfo_t info;
	int signo, code;

	if ((regs->ps & ~IPL_MAX) == 0) {
		if (type == 1) {
			const unsigned int *data
			  = (const unsigned int *) regs->pc;
			printk("Kernel bug at %s:%d\n",
			       (const char *)(data[1] | (long)data[2] << 32), 
			       data[0]);
		}
		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
			      regs, type, NULL);
	}

	switch (type) {
	      case 0: /*            */
		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_trapno = 0;
		info.si_addr = (void __user *) regs->pc;

		if (ptrace_cancel_bpt(current)) {
			regs->pc -= 4;	/*                             */
		}

		send_sig_info(SIGTRAP, &info, current);
		return;

	      case 1: /*          */
		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = __SI_FAULT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
		return;
		
	      case 2: /*         */
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = regs->r16;
		switch ((long) regs->r16) {
		case GEN_INTOVF:
			signo = SIGFPE;
			code = FPE_INTOVF;
			break;
		case GEN_INTDIV:
			signo = SIGFPE;
			code = FPE_INTDIV;
			break;
		case GEN_FLTOVF:
			signo = SIGFPE;
			code = FPE_FLTOVF;
			break;
		case GEN_FLTDIV:
			signo = SIGFPE;
			code = FPE_FLTDIV;
			break;
		case GEN_FLTUND:
			signo = SIGFPE;
			code = FPE_FLTUND;
			break;
		case GEN_FLTINV:
			signo = SIGFPE;
			code = FPE_FLTINV;
			break;
		case GEN_FLTINE:
			signo = SIGFPE;
			code = FPE_FLTRES;
			break;
		case GEN_ROPRAND:
			signo = SIGFPE;
			code = __SI_FAULT;
			break;

		case GEN_DECOVF:
		case GEN_DECDIV:
		case GEN_DECINV:
		case GEN_ASSERTERR:
		case GEN_NULPTRERR:
		case GEN_STKOVF:
		case GEN_STRLENERR:
		case GEN_SUBSTRERR:
		case GEN_RANGERR:
		case GEN_SUBRNG:
		case GEN_SUBRNG1:
		case GEN_SUBRNG2:
		case GEN_SUBRNG3:
		case GEN_SUBRNG4:
		case GEN_SUBRNG5:
		case GEN_SUBRNG6:
		case GEN_SUBRNG7:
		default:
			signo = SIGTRAP;
			code = __SI_FAULT;
			break;
		}

		info.si_signo = signo;
		info.si_errno = 0;
		info.si_code = code;
		info.si_addr = (void __user *) regs->pc;
		send_sig_info(signo, &info, current);
		return;

	      case 4: /*       */
		if (implver() == IMPLVER_EV4) {
			long si_code;

			/*                                       
                                                    
                                                   
                                                      
                                                  
                                                   
                                                   
                                         */
			regs->pc += opDEC_fix; 
			
			/*                                              
                                                  
                                              */
			si_code = alpha_fp_emul(regs->pc - 4);
			if (si_code == 0)
				return;
			if (si_code > 0) {
				info.si_signo = SIGFPE;
				info.si_errno = 0;
				info.si_code = si_code;
				info.si_addr = (void __user *) regs->pc;
				send_sig_info(SIGFPE, &info, current);
				return;
			}
		}
		break;

	      case 3: /*           */
		/*                                                    
                                                       
                                                      
                                          

                                                           
                                                          
                                                           
               */
		current_thread_info()->pcb.flags |= 1;
		__reload_thread(&current_thread_info()->pcb);
		return;

	      case 5: /*       */
	      default: /*                                   */
		      ;
	}

	info.si_signo = SIGILL;
	info.si_errno = 0;
	info.si_code = ILL_ILLOPC;
	info.si_addr = (void __user *) regs->pc;
	send_sig_info(SIGILL, &info, current);
}
コード例 #15
0
ファイル: signal.c プロジェクト: iPodLinux/linux-2.6.7-ipod
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
    siginfo_t info;
    int signr;

    /*
     * We want the common case to go fast, which
     * is why we may in certain cases get here from
     * kernel mode. Just return without doing anything
     * if so.
     */
    if (!user_mode(regs))
        return 0;

    if (current->flags & PF_FREEZE) {
        refrigerator(0);
        goto no_signal;
    }

    if (current->ptrace & PT_SINGLESTEP)
        ptrace_cancel_bpt(current);

    signr = get_signal_to_deliver(&info, regs, NULL);
    if (signr > 0) {
        handle_signal(signr, &info, oldset, regs, syscall);
        if (current->ptrace & PT_SINGLESTEP)
            ptrace_set_bpt(current);
        return 1;
    }

no_signal:
    /*
     * No signal to deliver to the process - restart the syscall.
     */
    if (syscall) {
        if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
            if (thumb_mode(regs)) {
                regs->ARM_r7 = __NR_restart_syscall;
                regs->ARM_pc -= 2;
            } else {
                u32 __user *usp;

                regs->ARM_sp -= 12;
                usp = (u32 __user *)regs->ARM_sp;

                put_user(regs->ARM_pc, &usp[0]);
                /* swi __NR_restart_syscall */
                put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
                /* ldr	pc, [sp], #12 */
                put_user(0xe49df00c, &usp[2]);

                flush_icache_range((unsigned long)usp,
                                   (unsigned long)(usp + 3));

                regs->ARM_pc = regs->ARM_sp + 4;
            }
        }
        if (regs->ARM_r0 == -ERESTARTNOHAND ||
                regs->ARM_r0 == -ERESTARTSYS ||
                regs->ARM_r0 == -ERESTARTNOINTR) {
            restart_syscall(regs);
        }
    }
    if (current->ptrace & PT_SINGLESTEP)
        ptrace_set_bpt(current);
    return 0;
}
コード例 #16
0
asmlinkage void
do_entIF(unsigned long type, unsigned long a1,
	 unsigned long a2, unsigned long a3, unsigned long a4,
	 unsigned long a5, struct pt_regs regs)
{
	if (!opDEC_testing || type != 4) {
		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
		      &regs, type, 0);
	}

	switch (type) {
	      case 0: /* breakpoint */
		if (ptrace_cancel_bpt(current)) {
			regs.pc -= 4;	/* make pc point to former bpt */
		}
		send_sig(SIGTRAP, current, 1);
		return;

	      case 1: /* bugcheck */
		send_sig(SIGTRAP, current, 1);
		return;

	      case 2: /* gentrap */
		/*
		 * The exception code should be passed on to the signal
		 * handler as the second argument.  Linux doesn't do that
		 * yet (also notice that Linux *always* behaves like
		 * DEC Unix with SA_SIGINFO off; see DEC Unix man page
		 * for sigaction(2)).
		 */
		switch ((long) regs.r16) {
		      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
		      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
		      case GEN_FLTINE: case GEN_ROPRAND:
			send_sig(SIGFPE, current, 1);
			return;

		      case GEN_DECOVF:
		      case GEN_DECDIV:
		      case GEN_DECINV:
		      case GEN_ASSERTERR:
		      case GEN_NULPTRERR:
		      case GEN_STKOVF:
		      case GEN_STRLENERR:
		      case GEN_SUBSTRERR:
		      case GEN_RANGERR:
		      case GEN_SUBRNG:
		      case GEN_SUBRNG1:
		      case GEN_SUBRNG2:
		      case GEN_SUBRNG3:
		      case GEN_SUBRNG4:
		      case GEN_SUBRNG5:
		      case GEN_SUBRNG6:
		      case GEN_SUBRNG7:
			send_sig(SIGTRAP, current, 1);
			return;
		}
		break;

	      case 4: /* opDEC */
		if (implver() == IMPLVER_EV4) {
			/* The some versions of SRM do not handle
			   the opDEC properly - they return the PC of the
			   opDEC fault, not the instruction after as the
			   Alpha architecture requires.  Here we fix it up.
			   We do this by intentionally causing an opDEC
			   fault during the boot sequence and testing if
			   we get the correct PC.  If not, we set a flag
			   to correct it every time through.
			*/
			if (opDEC_testing) {
				if (regs.pc == opDEC_test_pc) {
					opDEC_fix = 4;
					regs.pc += 4;
					printk("opDEC fixup enabled.\n");
				}
				return;
			}
			regs.pc += opDEC_fix; 
			
			/* EV4 does not implement anything except normal
			   rounding.  Everything else will come here as
			   an illegal instruction.  Emulate them.  */
			if (alpha_fp_emul(regs.pc-4))
				return;
		}
		break;

	      case 3: /* FEN fault */
		/* Irritating users can call PAL_clrfen to disable the
		   FPU for the process.  The kernel will then trap in
		   do_switch_stack and undo_switch_stack when we try
		   to save and restore the FP registers.

		   Given that GCC by default generates code that uses the
		   FP registers, PAL_clrfen is not useful except for DoS
		   attacks.  So turn the bleeding FPU back on and be done
		   with it.  */
		current->thread.pal_flags |= 1;
		__reload_thread(&current->thread);
		return;

	      case 5: /* illoc */
	      default: /* unexpected instruction-fault type */
		      ;
	}
	send_sig(SIGILL, current, 1);
}
コード例 #17
0
asmlinkage void
do_entIF(unsigned long type, struct pt_regs *regs)
{
	siginfo_t info;
	int signo, code;

	if ((regs->ps & ~IPL_MAX) == 0) {
		if (type == 1) {
			const unsigned int *data
			  = (const unsigned int *) regs->pc;
			printk("Kernel bug at %s:%d\n",
			       (const char *)(data[1] | (long)data[2] << 32),
			       data[0]);
		}
		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
			      regs, type, NULL);
	}

	switch (type) {
	      case 0: /* breakpoint */
		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = TRAP_BRKPT;
		info.si_trapno = 0;
		info.si_addr = (void __user *) regs->pc;

		if (ptrace_cancel_bpt(current)) {
			regs->pc -= 4;	/* make pc point to former bpt */
		}

		send_sig_info(SIGTRAP, &info, current);
		return;

	      case 1: /* bugcheck */
		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = __SI_FAULT;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
		return;

	      case 2: /* gentrap */
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = regs->r16;
		switch ((long) regs->r16) {
		case GEN_INTOVF:
			signo = SIGFPE;
			code = FPE_INTOVF;
			break;
		case GEN_INTDIV:
			signo = SIGFPE;
			code = FPE_INTDIV;
			break;
		case GEN_FLTOVF:
			signo = SIGFPE;
			code = FPE_FLTOVF;
			break;
		case GEN_FLTDIV:
			signo = SIGFPE;
			code = FPE_FLTDIV;
			break;
		case GEN_FLTUND:
			signo = SIGFPE;
			code = FPE_FLTUND;
			break;
		case GEN_FLTINV:
			signo = SIGFPE;
			code = FPE_FLTINV;
			break;
		case GEN_FLTINE:
			signo = SIGFPE;
			code = FPE_FLTRES;
			break;
		case GEN_ROPRAND:
			signo = SIGFPE;
			code = __SI_FAULT;
			break;

		case GEN_DECOVF:
		case GEN_DECDIV:
		case GEN_DECINV:
		case GEN_ASSERTERR:
		case GEN_NULPTRERR:
		case GEN_STKOVF:
		case GEN_STRLENERR:
		case GEN_SUBSTRERR:
		case GEN_RANGERR:
		case GEN_SUBRNG:
		case GEN_SUBRNG1:
		case GEN_SUBRNG2:
		case GEN_SUBRNG3:
		case GEN_SUBRNG4:
		case GEN_SUBRNG5:
		case GEN_SUBRNG6:
		case GEN_SUBRNG7:
		default:
			signo = SIGTRAP;
			code = __SI_FAULT;
			break;
		}

		info.si_signo = signo;
		info.si_errno = 0;
		info.si_code = code;
		info.si_addr = (void __user *) regs->pc;
		send_sig_info(signo, &info, current);
		return;

	      case 4: /* opDEC */
		if (implver() == IMPLVER_EV4) {
			long si_code;

			/* The some versions of SRM do not handle
			   the opDEC properly - they return the PC of the
			   opDEC fault, not the instruction after as the
			   Alpha architecture requires.  Here we fix it up.
			   We do this by intentionally causing an opDEC
			   fault during the boot sequence and testing if
			   we get the correct PC.  If not, we set a flag
			   to correct it every time through.  */
			regs->pc += opDEC_fix;

			/* EV4 does not implement anything except normal
			   rounding.  Everything else will come here as
			   an illegal instruction.  Emulate them.  */
			si_code = alpha_fp_emul(regs->pc - 4);
			if (si_code == 0)
				return;
			if (si_code > 0) {
				info.si_signo = SIGFPE;
				info.si_errno = 0;
				info.si_code = si_code;
				info.si_addr = (void __user *) regs->pc;
				send_sig_info(SIGFPE, &info, current);
				return;
			}
		}
		break;

	      case 3: /* FEN fault */
		/* Irritating users can call PAL_clrfen to disable the
		   FPU for the process.  The kernel will then trap in
		   do_switch_stack and undo_switch_stack when we try
		   to save and restore the FP registers.

		   Given that GCC by default generates code that uses the
		   FP registers, PAL_clrfen is not useful except for DoS
		   attacks.  So turn the bleeding FPU back on and be done
		   with it.  */
		current_thread_info()->pcb.flags |= 1;
		__reload_thread(&current_thread_info()->pcb);
		return;

	      case 5: /* illoc */
	      default: /* unexpected instruction-fault type */
		      ;
	}

	info.si_signo = SIGILL;
	info.si_errno = 0;
	info.si_code = ILL_ILLOPC;
	info.si_addr = (void __user *) regs->pc;
	send_sig_info(SIGILL, &info, current);
}
コード例 #18
0
ファイル: traps.c プロジェクト: chinnyannieb/empeg-hijack
asmlinkage void
do_entIF(unsigned long type, unsigned long a1,
	 unsigned long a2, unsigned long a3, unsigned long a4,
	 unsigned long a5, struct pt_regs regs)
{
	die_if_kernel("Instruction fault", &regs, type, 0);
	switch (type) {
	      case 0: /* breakpoint */
		if (ptrace_cancel_bpt(current)) {
			regs.pc -= 4;	/* make pc point to former bpt */
		}
		send_sig(SIGTRAP, current, 1);
		break;

	      case 1: /* bugcheck */
		send_sig(SIGTRAP, current, 1);
		break;

	      case 2: /* gentrap */
		/*
		 * The exception code should be passed on to the signal
		 * handler as the second argument.  Linux doesn't do that
		 * yet (also notice that Linux *always* behaves like
		 * DEC Unix with SA_SIGINFO off; see DEC Unix man page
		 * for sigaction(2)).
		 */
		switch ((long) regs.r16) {
		      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
		      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
		      case GEN_FLTINE: case GEN_ROPRAND:
			send_sig(SIGFPE, current, 1);
			break;

		      case GEN_DECOVF:
		      case GEN_DECDIV:
		      case GEN_DECINV:
		      case GEN_ASSERTERR:
		      case GEN_NULPTRERR:
		      case GEN_STKOVF:
		      case GEN_STRLENERR:
		      case GEN_SUBSTRERR:
		      case GEN_RANGERR:
		      case GEN_SUBRNG:
		      case GEN_SUBRNG1:
		      case GEN_SUBRNG2:
		      case GEN_SUBRNG3:
		      case GEN_SUBRNG4:
		      case GEN_SUBRNG5:
		      case GEN_SUBRNG6:
		      case GEN_SUBRNG7:
			send_sig(SIGTRAP, current, 1);
			break;
		}
		break;

	      case 3: /* FEN fault */
		send_sig(SIGILL, current, 1);
		break;

	      case 4: /* opDEC */
		if (implver() == IMPLVER_EV4) {
			/* EV4 does not implement anything except normal
			   rounding.  Everything else will come here as
			   an illegal instruction.  Emulate them.  */
			if (alpha_fp_emul(regs.pc - 4))
				return;
		}
		send_sig(SIGILL, current, 1);
		break;

	      default:
		panic("do_entIF: unexpected instruction-fault type");
	}
}
コード例 #19
0
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 *
 * "r0" and "r19" are the registers we need to restore for system call
 * restart. "r0" is also used as an indicator whether we can restart at
 * all (if we get here from anything but a syscall return, it will be 0)
 */
static void
do_signal(struct pt_regs * regs, struct switch_stack * sw,
	  unsigned long r0, unsigned long r19)
{
	siginfo_t info;
	int signr;
	unsigned long single_stepping = ptrace_cancel_bpt(current);
	struct k_sigaction ka;
	sigset_t *oldset;

	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	/* This lets the debugger run, ... */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);

	/* ... so re-check the single stepping. */
	single_stepping |= ptrace_cancel_bpt(current);

	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
		if (r0)
			syscall_restart(r0, r19, regs, &ka);
		if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
			/* A signal was successfully delivered, and the
			   saved sigmask was stored on the signal frame,
			   and will be restored by sigreturn.  So we can
			   simply clear the restore sigmask flag.  */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);
		}
		if (single_stepping) 
			ptrace_set_bpt(current); /* re-set bpt */
		return;
	}

	if (r0) {
	  	switch (regs->r0) {
		case ERESTARTNOHAND:
		case ERESTARTSYS:
		case ERESTARTNOINTR:
			/* Reset v0 and a3 and replay syscall.  */
			regs->r0 = r0;
			regs->r19 = r19;
			regs->pc -= 4;
			break;
		case ERESTART_RESTARTBLOCK:
			/* Force v0 to the restart syscall and reply.  */
			regs->r0 = __NR_restart_syscall;
			regs->pc -= 4;
			break;
		}
	}

	/* If there's no signal to deliver, we just restore the saved mask.  */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}

	if (single_stepping)
		ptrace_set_bpt(current);	/* re-set breakpoint */
}
コード例 #20
0
ファイル: signal.c プロジェクト: gtvhacker/Logitech-Revue
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
	struct k_sigaction ka;
	siginfo_t info;
	int signr;

#ifdef CONFIG_PREEMPT_RT
	/*
	 * Fully-preemptible kernel does not need interrupts disabled:
	 */
	local_irq_enable();
	preempt_check_resched();
#endif

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return 0;

	if (try_to_freeze())
		goto no_signal;

	if (current->ptrace & PT_SINGLESTEP)
		ptrace_cancel_bpt(current);

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		handle_signal(signr, &ka, &info, oldset, regs, syscall);
		if (current->ptrace & PT_SINGLESTEP)
			ptrace_set_bpt(current);
		return 1;
	}

 no_signal:
	/*
	 * No signal to deliver to the process - restart the syscall.
	 */
	if (syscall) {
		if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
			if (thumb_mode(regs)) {
				regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
				regs->ARM_pc -= 2;
			} else {
#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
				regs->ARM_r7 = __NR_restart_syscall;
				regs->ARM_pc -= 4;
#else
				u32 __user *usp;
				u32 swival = __NR_restart_syscall;

				regs->ARM_sp -= 12;
				usp = (u32 __user *)regs->ARM_sp;

				/*
				 * Either we supports OABI only, or we have
				 * EABI with the OABI compat layer enabled.
				 * In the later case we don't know if user
				 * space is EABI or not, and if not we must
				 * not clobber r7.  Always using the OABI
				 * syscall solves that issue and works for
				 * all those cases.
				 */
				swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE;

				put_user(regs->ARM_pc, &usp[0]);
				/* swi __NR_restart_syscall */
				put_user(0xef000000 | swival, &usp[1]);
				/* ldr	pc, [sp], #12 */
				put_user(0xe49df00c, &usp[2]);

				flush_icache_range((unsigned long)usp,
						   (unsigned long)(usp + 3));

				regs->ARM_pc = regs->ARM_sp + 4;
#endif
			}
		}
		if (regs->ARM_r0 == -ERESTARTNOHAND ||
		    regs->ARM_r0 == -ERESTARTSYS ||
		    regs->ARM_r0 == -ERESTARTNOINTR) {
			restart_syscall(regs);
		}
	}
	if (current->ptrace & PT_SINGLESTEP)
		ptrace_set_bpt(current);
	return 0;
}
コード例 #21
0
ファイル: signal.c プロジェクト: dmgerman/linux-pre-history
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
	struct k_sigaction *ka;
	siginfo_t info;
	int single_stepping;

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return 0;

	if (!oldset)
		oldset = &current->blocked;

	single_stepping = ptrace_cancel_bpt(current);

	for (;;) {
		unsigned long signr;

		spin_lock_irq (&current->sigmask_lock);
		signr = dequeue_signal(&current->blocked, &info);
		spin_unlock_irq (&current->sigmask_lock);

		if (!signr)
			break;

		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
			/* Let the debugger run.  */
			current->exit_code = signr;
			current->state = TASK_STOPPED;
			notify_parent(current, SIGCHLD);
			schedule();
			single_stepping |= ptrace_cancel_bpt(current);

			/* We're back.  Did the debugger cancel the sig?  */
			if (!(signr = current->exit_code))
				continue;
			current->exit_code = 0;

			/* The debugger continued.  Ignore SIGSTOP.  */
			if (signr == SIGSTOP)
				continue;

			/* Update the siginfo structure.  Is this good? */
			if (signr != info.si_signo) {
				info.si_signo = signr;
				info.si_errno = 0;
				info.si_code = SI_USER;
				info.si_pid = current->p_pptr->pid;
				info.si_uid = current->p_pptr->uid;
			}

			/* If the (new) signal is now blocked, requeue it.  */
			if (sigismember(&current->blocked, signr)) {
				send_sig_info(signr, &info, current);
				continue;
			}
		}

		ka = &current->sig->action[signr-1];
		if (ka->sa.sa_handler == SIG_IGN) {
			if (signr != SIGCHLD)
				continue;
			/* Check for SIGCHLD: it's special.  */
			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
				/* nothing */;
			continue;
		}

		if (ka->sa.sa_handler == SIG_DFL) {
			int exit_code = signr;

			/* Init gets no signals it doesn't want.  */
			if (current->pid == 1)
				continue;

			switch (signr) {
			case SIGCONT: case SIGCHLD: case SIGWINCH:
				continue;

			case SIGTSTP: case SIGTTIN: case SIGTTOU:
				if (is_orphaned_pgrp(current->pgrp))
					continue;
				/* FALLTHRU */

			case SIGSTOP:
				current->state = TASK_STOPPED;
				current->exit_code = signr;
				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
					notify_parent(current, SIGCHLD);
				schedule();
				continue;

			case SIGQUIT: case SIGILL: case SIGTRAP:
			case SIGABRT: case SIGFPE: case SIGSEGV:
			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
				if (do_coredump(signr, regs))
					exit_code |= 0x80;
				/* FALLTHRU */

			default:
				sigaddset(&current->pending.signal, signr);
				recalc_sigpending(current);
				current->flags |= PF_SIGNALED;
				do_exit(exit_code);
				/* NOTREACHED */
			}
		}

		/* Are we from a system call? */
		if (syscall) {
			switch (regs->ARM_r0) {
			case -ERESTARTNOHAND:
				regs->ARM_r0 = -EINTR;
				break;

			case -ERESTARTSYS:
				if (!(ka->sa.sa_flags & SA_RESTART)) {
					regs->ARM_r0 = -EINTR;
					break;
				}
				/* fallthrough */
			case -ERESTARTNOINTR:
				regs->ARM_r0 = regs->ARM_ORIG_r0;
				regs->ARM_pc -= 4;
			}
		}
		/* Whee!  Actually deliver the signal.  */
		handle_signal(signr, ka, &info, oldset, regs);
		if (single_stepping)
		    	ptrace_set_bpt(current);
		return 1;
	}

	if (syscall &&
	    (regs->ARM_r0 == -ERESTARTNOHAND ||
	     regs->ARM_r0 == -ERESTARTSYS ||
	     regs->ARM_r0 == -ERESTARTNOINTR)) {
		regs->ARM_r0 = regs->ARM_ORIG_r0;
		regs->ARM_pc -= 4;
	}
	if (single_stepping)
		ptrace_set_bpt(current);
	return 0;
}
コード例 #22
0
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
    struct k_sigaction ka;
    siginfo_t info;
    int signr;

    /*
     * We want the common case to go fast, which
     * is why we may in certain cases get here from
     * kernel mode. Just return without doing anything
     * if so.
     */
    if (!user_mode(regs))
        return 0;

    if (try_to_freeze())
        goto no_signal;

    /*
     *FIXME: I don't know how to trace TriMedia executable.
     */
#if 0
    if (current->ptrace & PT_SINGLESTEP)
        ptrace_cancel_bpt(current);
#endif

    signr = get_signal_to_deliver(&info, &ka, regs, NULL);
    if (signr > 0) {
        handle_signal(signr, &ka, &info, oldset, regs, syscall);
        /*
         *FIXME: I don't know how to trace TriMedia executable.
         */
#if 0
        if (current->ptrace & PT_SINGLESTEP)
            ptrace_set_bpt(current);
#endif
        return 1;
    }

no_signal:
    /*
     * No signal to deliver to the process - restart the syscall.
     */
    if (syscall) {
        if (regs->r5 == -ERESTART_RESTARTBLOCK) {
            regs->r5=__NR_restart_syscall;
            regs->dpc=regs->spc;
        }
        if (regs->r5 == -ERESTARTNOHAND ||
                regs->r5 == -ERESTARTSYS ||
                regs->r5 == -ERESTARTNOINTR) {
            restart_syscall(regs);
        }
    }

    /*
     *FIXME: I don't know how to trace TriMedia executable.
     */
#if 0
    if (current->ptrace & PT_SINGLESTEP)
        ptrace_set_bpt(current);
#endif
    return 0;
}
コード例 #23
0
ファイル: signal.c プロジェクト: dot-Sean/linux_kernels
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 *
 * "r0" and "r19" are the registers we need to restore for system call
 * restart. "r0" is also used as an indicator whether we can restart at
 * all (if we get here from anything but a syscall return, it will be 0)
 */
asmlinkage int
do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
          unsigned long r0, unsigned long r19)
{
    unsigned long single_stepping = ptrace_cancel_bpt(current);

    if (!oldset)
        oldset = &current->blocked;

    while (1) {
        unsigned long signr;
        struct k_sigaction *ka;
        siginfo_t info;

        spin_lock_irq(&current->sigmask_lock);
        signr = dequeue_signal(&current->blocked, &info);
        spin_unlock_irq(&current->sigmask_lock);

        if (!signr)
            break;

        if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
            /* Let the debugger run.  */
            current->exit_code = signr;
            current->state = TASK_STOPPED;
            notify_parent(current, SIGCHLD);
            schedule();
            single_stepping |= ptrace_cancel_bpt(current);

            /* We're back.  Did the debugger cancel the sig?  */
            if (!(signr = current->exit_code))
                continue;
            current->exit_code = 0;

            /* The debugger continued.  Ignore SIGSTOP.  */
            if (signr == SIGSTOP)
                continue;

            /* Update the siginfo structure.  Is this good?  */
            if (signr != info.si_signo) {
                info.si_signo = signr;
                info.si_errno = 0;
                info.si_code = SI_USER;
                info.si_pid = current->p_pptr->pid;
                info.si_uid = current->p_pptr->uid;
            }

            /* If the (new) signal is now blocked, requeue it.  */
            if (sigismember(&current->blocked, signr)) {
                send_sig_info(signr, &info, current);
                continue;
            }
        }

        ka = &current->sig->action[signr-1];
        if (ka->sa.sa_handler == SIG_IGN) {
            if (signr != SIGCHLD)
                continue;
            /* Check for SIGCHLD: it's special.  */
            while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
                /* nothing */;
            continue;
        }

        if (ka->sa.sa_handler == SIG_DFL) {
            int exit_code = signr & 0x7f;

            /* Init gets no signals it doesn't want.  */
            if (current->pid == 1)
                continue;

            switch (signr) {
            case SIGCONT:
            case SIGCHLD:
            case SIGWINCH:
                continue;

            case SIGTSTP:
            case SIGTTIN:
            case SIGTTOU:
                if (is_orphaned_pgrp(current->pgrp))
                    continue;
            /* FALLTHRU */

            case SIGSTOP:
                current->state = TASK_STOPPED;
                current->exit_code = signr;
                if (!(current->p_pptr->sig->action[SIGCHLD-1]
                        .sa.sa_flags & SA_NOCLDSTOP))
                    notify_parent(current, SIGCHLD);
                schedule();
                single_stepping |= ptrace_cancel_bpt(current);
                continue;

            case SIGQUIT:
            case SIGILL:
            case SIGTRAP:
            case SIGABRT:
            case SIGFPE:
            case SIGSEGV:
            case SIGBUS:
            case SIGSYS:
            case SIGXCPU:
            case SIGXFSZ:
                if (do_coredump(signr, regs))
                    exit_code |= 0x80;
            /* FALLTHRU */

            default:
                lock_kernel();
                sigaddset(&current->pending.signal, signr);
                current->flags |= PF_SIGNALED;
                do_exit(exit_code);
                /* NOTREACHED */
            }
            continue;
        }

        /* Whee!  Actually deliver the signal.  */
        if (r0) syscall_restart(r0, r19, regs, ka);
        handle_signal(signr, ka, &info, oldset, regs, sw);
        if (single_stepping)
            ptrace_set_bpt(current); /* re-set bpt */
        return 1;
    }

    if (r0 &&
            (regs->r0 == ERESTARTNOHAND ||
             regs->r0 == ERESTARTSYS ||
             regs->r0 == ERESTARTNOINTR)) {
        regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
        regs->r19 = r19;
        regs->pc -= 4;
    }
    if (single_stepping)
        ptrace_set_bpt(current);	/* re-set breakpoint */

    return 0;
}