2006-07-10 04:45:13 -07:00
/*
2007-10-16 01:27:00 -07:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-16 15:20:36 -07:00
* Licensed under the GPL
*/
2008-02-04 22:31:14 -08:00
# include <linux/module.h>
# include <linux/ptrace.h>
# include <linux/sched.h>
# include <asm/siginfo.h>
# include <asm/signal.h>
# include <asm/unistd.h>
2005-04-16 15:20:36 -07:00
# include "frame_kern.h"
2007-10-16 01:27:00 -07:00
# include "kern_util.h"
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( block_signals ) ;
EXPORT_SYMBOL ( unblock_signals ) ;
/*
* OK , we ' re invoking a handler
2006-07-10 04:45:13 -07:00
*/
2012-05-21 23:42:15 -04:00
static void handle_signal ( struct pt_regs * regs , unsigned long signr ,
2012-05-02 09:59:21 -04:00
struct k_sigaction * ka , siginfo_t * info )
2005-04-16 15:20:36 -07:00
{
2012-05-02 09:59:21 -04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2012-09-06 13:39:47 -04:00
int singlestep = 0 ;
2005-04-16 15:20:36 -07:00
unsigned long sp ;
int err ;
2012-09-06 13:39:47 -04:00
if ( ( current - > ptrace & PT_DTRACE ) & & ( current - > ptrace & PT_PTRACED ) )
singlestep = 1 ;
2005-04-16 15:20:36 -07:00
/* Did we come from a system call? */
2007-10-16 01:27:00 -07:00
if ( PT_REGS_SYSCALL_NR ( regs ) > = 0 ) {
2005-04-16 15:20:36 -07:00
/* If so, check system call restarting.. */
2008-02-04 22:31:14 -08:00
switch ( PT_REGS_SYSCALL_RET ( regs ) ) {
2005-04-16 15:20:36 -07:00
case - ERESTART_RESTARTBLOCK :
case - ERESTARTNOHAND :
PT_REGS_SYSCALL_RET ( regs ) = - EINTR ;
break ;
case - ERESTARTSYS :
if ( ! ( ka - > sa . sa_flags & SA_RESTART ) ) {
PT_REGS_SYSCALL_RET ( regs ) = - EINTR ;
break ;
}
/* fallthrough */
case - ERESTARTNOINTR :
PT_REGS_RESTART_SYSCALL ( regs ) ;
PT_REGS_ORIG_SYSCALL ( regs ) = PT_REGS_SYSCALL_NR ( regs ) ;
break ;
}
}
sp = PT_REGS_SP ( regs ) ;
2007-10-16 01:27:00 -07:00
if ( ( ka - > sa . sa_flags & SA_ONSTACK ) & & ( sas_ss_flags ( sp ) = = 0 ) )
2005-04-16 15:20:36 -07:00
sp = current - > sas_ss_sp + current - > sas_ss_size ;
# ifdef CONFIG_ARCH_HAS_SC_SIGNALS
2007-10-16 01:27:00 -07:00
if ( ! ( ka - > sa . sa_flags & SA_SIGINFO ) )
2005-04-16 15:20:36 -07:00
err = setup_signal_stack_sc ( sp , signr , ka , regs , oldset ) ;
else
# endif
err = setup_signal_stack_si ( sp , signr , ka , regs , info , oldset ) ;
2012-03-23 15:01:49 -07:00
if ( err )
2005-04-16 15:20:36 -07:00
force_sigsegv ( signr , current ) ;
2012-03-23 15:01:50 -07:00
else
2012-09-06 13:39:47 -04:00
signal_delivered ( signr , info , ka , regs , singlestep ) ;
2005-04-16 15:20:36 -07:00
}
2006-01-18 17:44:02 -08:00
static int kern_do_signal ( struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
struct k_sigaction ka_copy ;
siginfo_t info ;
int sig , handled_sig = 0 ;
2007-10-16 01:27:00 -07:00
while ( ( sig = get_signal_to_deliver ( & info , & ka_copy , regs , NULL ) ) > 0 ) {
2005-04-16 15:20:36 -07:00
handled_sig = 1 ;
/* Whee! Actually deliver the signal. */
2012-05-21 23:42:15 -04:00
handle_signal ( regs , sig , & ka_copy , & info ) ;
2005-04-16 15:20:36 -07:00
}
/* Did we come from a system call? */
2007-10-16 01:27:00 -07:00
if ( ! handled_sig & & ( PT_REGS_SYSCALL_NR ( regs ) > = 0 ) ) {
2005-04-16 15:20:36 -07:00
/* Restart the system call - no handlers present */
2008-02-04 22:31:14 -08:00
switch ( PT_REGS_SYSCALL_RET ( regs ) ) {
2006-01-18 17:44:02 -08:00
case - ERESTARTNOHAND :
case - ERESTARTSYS :
case - ERESTARTNOINTR :
2005-04-16 15:20:36 -07:00
PT_REGS_ORIG_SYSCALL ( regs ) = PT_REGS_SYSCALL_NR ( regs ) ;
PT_REGS_RESTART_SYSCALL ( regs ) ;
2006-01-18 17:44:02 -08:00
break ;
case - ERESTART_RESTARTBLOCK :
2006-07-10 04:45:13 -07:00
PT_REGS_ORIG_SYSCALL ( regs ) = __NR_restart_syscall ;
2005-04-16 15:20:36 -07:00
PT_REGS_RESTART_SYSCALL ( regs ) ;
2006-01-18 17:44:02 -08:00
break ;
2007-10-16 01:27:00 -07:00
}
2005-04-16 15:20:36 -07:00
}
2007-10-16 01:27:00 -07:00
/*
* This closes a way to execute a system call on the host . If
2005-04-16 15:20:36 -07:00
* you set a breakpoint on a system call instruction and singlestep
* from it , the tracing thread used to PTRACE_SINGLESTEP the process
* rather than PTRACE_SYSCALL it , allowing the system call to execute
2006-07-10 04:45:13 -07:00
* on the host . The tracing thread will check this flag and
2005-04-16 15:20:36 -07:00
* PTRACE_SYSCALL if necessary .
*/
2007-10-16 01:27:00 -07:00
if ( current - > ptrace & PT_DTRACE )
2005-04-16 15:20:36 -07:00
current - > thread . singlestep_syscall =
is_syscall ( PT_REGS_IP ( & current - > thread . regs ) ) ;
2006-01-18 17:44:02 -08:00
2007-10-16 01:27:00 -07:00
/*
* if there ' s no signal to deliver , we just put the saved sigmask
* back
*/
2012-05-21 23:33:55 -04:00
if ( ! handled_sig )
restore_saved_sigmask ( ) ;
2007-03-06 01:42:18 -08:00
return handled_sig ;
2005-04-16 15:20:36 -07:00
}
int do_signal ( void )
{
2007-03-06 01:42:18 -08:00
return kern_do_signal ( & current - > thread . regs ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Atomically swap in the new signal mask , and wait for a signal .
*/
long sys_sigsuspend ( int history0 , int history1 , old_sigset_t mask )
{
2012-03-23 15:01:50 -07:00
sigset_t blocked ;
siginitset ( & blocked , mask ) ;
2012-05-21 21:42:32 -04:00
return sigsuspend ( & blocked ) ;
2005-04-16 15:20:36 -07:00
}
long sys_sigaltstack ( const stack_t __user * uss , stack_t __user * uoss )
{
2007-03-06 01:42:18 -08:00
return do_sigaltstack ( uss , uoss , PT_REGS_SP ( & current - > thread . regs ) ) ;
2005-04-16 15:20:36 -07:00
}