2006-07-10 15:45:13 +04:00
/*
2007-10-16 12:27:00 +04:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-17 02:20:36 +04:00
* Licensed under the GPL
*/
2008-02-05 09:31:14 +03: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>
2012-10-08 06:27:32 +04:00
# include <frame_kern.h>
# include <kern_util.h>
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( block_signals ) ;
EXPORT_SYMBOL ( unblock_signals ) ;
/*
* OK , we ' re invoking a handler
2006-07-10 15:45:13 +04:00
*/
2013-10-06 23:57:10 +04:00
static void handle_signal ( struct ksignal * ksig , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2012-05-02 17:59:21 +04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2012-09-06 21:39:47 +04:00
int singlestep = 0 ;
2005-04-17 02:20:36 +04:00
unsigned long sp ;
int err ;
2012-09-06 21:39:47 +04:00
if ( ( current - > ptrace & PT_DTRACE ) & & ( current - > ptrace & PT_PTRACED ) )
singlestep = 1 ;
2005-04-17 02:20:36 +04:00
/* Did we come from a system call? */
2007-10-16 12:27:00 +04:00
if ( PT_REGS_SYSCALL_NR ( regs ) > = 0 ) {
2005-04-17 02:20:36 +04:00
/* If so, check system call restarting.. */
2008-02-05 09:31:14 +03:00
switch ( PT_REGS_SYSCALL_RET ( regs ) ) {
2005-04-17 02:20:36 +04:00
case - ERESTART_RESTARTBLOCK :
case - ERESTARTNOHAND :
PT_REGS_SYSCALL_RET ( regs ) = - EINTR ;
break ;
case - ERESTARTSYS :
2013-10-06 23:57:10 +04:00
if ( ! ( ksig - > ka . sa . sa_flags & SA_RESTART ) ) {
2005-04-17 02:20:36 +04:00
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 ) ;
2013-10-06 23:57:10 +04:00
if ( ( ksig - > ka . sa . sa_flags & SA_ONSTACK ) & & ( sas_ss_flags ( sp ) = = 0 ) )
2005-04-17 02:20:36 +04:00
sp = current - > sas_ss_sp + current - > sas_ss_size ;
# ifdef CONFIG_ARCH_HAS_SC_SIGNALS
2013-10-06 23:57:10 +04:00
if ( ! ( ksig - > ka . sa . sa_flags & SA_SIGINFO ) )
err = setup_signal_stack_sc ( sp , ksig , regs , oldset ) ;
2005-04-17 02:20:36 +04:00
else
# endif
2013-10-06 23:57:10 +04:00
err = setup_signal_stack_si ( sp , ksig , regs , oldset ) ;
2005-04-17 02:20:36 +04:00
2013-10-06 23:57:10 +04:00
signal_setup_done ( err , ksig , singlestep ) ;
2005-04-17 02:20:36 +04:00
}
2015-07-03 22:44:20 +03:00
void do_signal ( struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2013-10-06 23:57:10 +04:00
struct ksignal ksig ;
int handled_sig = 0 ;
2005-04-17 02:20:36 +04:00
2016-01-26 01:33:30 +03:00
while ( get_signal ( & ksig ) ) {
2005-04-17 02:20:36 +04:00
handled_sig = 1 ;
/* Whee! Actually deliver the signal. */
2013-10-06 23:57:10 +04:00
handle_signal ( & ksig , regs ) ;
2005-04-17 02:20:36 +04:00
}
/* Did we come from a system call? */
2007-10-16 12:27:00 +04:00
if ( ! handled_sig & & ( PT_REGS_SYSCALL_NR ( regs ) > = 0 ) ) {
2005-04-17 02:20:36 +04:00
/* Restart the system call - no handlers present */
2008-02-05 09:31:14 +03:00
switch ( PT_REGS_SYSCALL_RET ( regs ) ) {
2006-01-19 04:44:02 +03:00
case - ERESTARTNOHAND :
case - ERESTARTSYS :
case - ERESTARTNOINTR :
2005-04-17 02:20:36 +04:00
PT_REGS_ORIG_SYSCALL ( regs ) = PT_REGS_SYSCALL_NR ( regs ) ;
PT_REGS_RESTART_SYSCALL ( regs ) ;
2006-01-19 04:44:02 +03:00
break ;
case - ERESTART_RESTARTBLOCK :
2006-07-10 15:45:13 +04:00
PT_REGS_ORIG_SYSCALL ( regs ) = __NR_restart_syscall ;
2005-04-17 02:20:36 +04:00
PT_REGS_RESTART_SYSCALL ( regs ) ;
2006-01-19 04:44:02 +03:00
break ;
2007-10-16 12:27:00 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:27:00 +04:00
/*
* This closes a way to execute a system call on the host . If
2005-04-17 02:20:36 +04: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 15:45:13 +04:00
* on the host . The tracing thread will check this flag and
2005-04-17 02:20:36 +04:00
* PTRACE_SYSCALL if necessary .
*/
2007-10-16 12:27:00 +04:00
if ( current - > ptrace & PT_DTRACE )
2005-04-17 02:20:36 +04:00
current - > thread . singlestep_syscall =
is_syscall ( PT_REGS_IP ( & current - > thread . regs ) ) ;
2006-01-19 04:44:02 +03:00
2007-10-16 12:27:00 +04:00
/*
* if there ' s no signal to deliver , we just put the saved sigmask
* back
*/
2012-05-22 07:33:55 +04:00
if ( ! handled_sig )
restore_saved_sigmask ( ) ;
2005-04-17 02:20:36 +04:00
}