2005-04-16 15:20:36 -07:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1992 Ross Biro
* Copyright ( C ) Linus Torvalds
* Copyright ( C ) 1994 , 95 , 96 , 97 , 98 , 2000 Ralf Baechle
* Copyright ( C ) 1996 David S . Miller
* Kevin D . Kissell , kevink @ mips . com and Carsten Langgaard , carstenl @ mips . com
* Copyright ( C ) 1999 MIPS Technologies , Inc .
* Copyright ( C ) 2000 Ulf Carlsson
*
* At this time Linux / MIPS64 only supports syscall tracing , even for 32 - bit
* binaries .
*/
# include <linux/compiler.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/errno.h>
# include <linux/ptrace.h>
# include <linux/smp.h>
# include <linux/user.h>
# include <linux/security.h>
2007-07-25 16:19:33 +01:00
# include <linux/audit.h>
# include <linux/seccomp.h>
2005-04-16 15:20:36 -07:00
2005-05-19 12:08:04 +00:00
# include <asm/byteorder.h>
2005-04-16 15:20:36 -07:00
# include <asm/cpu.h>
2005-05-31 11:49:19 +00:00
# include <asm/dsp.h>
2005-04-16 15:20:36 -07:00
# include <asm/fpu.h>
# include <asm/mipsregs.h>
2005-10-06 17:39:32 +01:00
# include <asm/mipsmtregs.h>
2005-04-16 15:20:36 -07:00
# include <asm/pgtable.h>
# include <asm/page.h>
# include <asm/system.h>
# include <asm/uaccess.h>
# include <asm/bootinfo.h>
2005-09-28 18:11:15 -04:00
# include <asm/reg.h>
2005-04-16 15:20:36 -07:00
/*
* Called by kernel / ptrace . c when detaching . .
*
* Make sure single step bits etc are not set .
*/
void ptrace_disable ( struct task_struct * child )
{
2008-09-23 00:11:26 -07:00
/* Don't load the watchpoint registers for the ex-child. */
clear_tsk_thread_flag ( child , TIF_LOAD_WATCH ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-28 18:11:15 -04:00
/*
* Read a general register set . We always use the 64 - bit format , even
* for 32 - bit kernels and for 32 - bit processes on a 64 - bit kernel .
* Registers are sign extended to fill the available space .
*/
2007-10-11 23:46:15 +01:00
int ptrace_getregs ( struct task_struct * child , __s64 __user * data )
2005-09-28 18:11:15 -04:00
{
struct pt_regs * regs ;
int i ;
if ( ! access_ok ( VERIFY_WRITE , data , 38 * 8 ) )
return - EIO ;
2006-01-12 01:06:07 -08:00
regs = task_pt_regs ( child ) ;
2005-09-28 18:11:15 -04:00
for ( i = 0 ; i < 32 ; i + + )
2007-10-26 00:53:02 +09:00
__put_user ( ( long ) regs - > regs [ i ] , data + i ) ;
__put_user ( ( long ) regs - > lo , data + EF_LO - EF_R0 ) ;
__put_user ( ( long ) regs - > hi , data + EF_HI - EF_R0 ) ;
__put_user ( ( long ) regs - > cp0_epc , data + EF_CP0_EPC - EF_R0 ) ;
__put_user ( ( long ) regs - > cp0_badvaddr , data + EF_CP0_BADVADDR - EF_R0 ) ;
__put_user ( ( long ) regs - > cp0_status , data + EF_CP0_STATUS - EF_R0 ) ;
__put_user ( ( long ) regs - > cp0_cause , data + EF_CP0_CAUSE - EF_R0 ) ;
2005-09-28 18:11:15 -04:00
return 0 ;
}
/*
* Write a general register set . As for PTRACE_GETREGS , we always use
* the 64 - bit format . On a 32 - bit kernel only the lower order half
* ( according to endianness ) will be used .
*/
2007-10-11 23:46:15 +01:00
int ptrace_setregs ( struct task_struct * child , __s64 __user * data )
2005-09-28 18:11:15 -04:00
{
struct pt_regs * regs ;
int i ;
if ( ! access_ok ( VERIFY_READ , data , 38 * 8 ) )
return - EIO ;
2006-01-12 01:06:07 -08:00
regs = task_pt_regs ( child ) ;
2005-09-28 18:11:15 -04:00
for ( i = 0 ; i < 32 ; i + + )
2007-10-11 23:46:15 +01:00
__get_user ( regs - > regs [ i ] , data + i ) ;
__get_user ( regs - > lo , data + EF_LO - EF_R0 ) ;
__get_user ( regs - > hi , data + EF_HI - EF_R0 ) ;
__get_user ( regs - > cp0_epc , data + EF_CP0_EPC - EF_R0 ) ;
2005-09-28 18:11:15 -04:00
/* badvaddr, status, and cause may not be written. */
return 0 ;
}
2007-10-11 23:46:15 +01:00
int ptrace_getfpregs ( struct task_struct * child , __u32 __user * data )
2005-09-28 18:11:15 -04:00
{
int i ;
2006-10-09 00:10:01 +09:00
unsigned int tmp ;
2005-09-28 18:11:15 -04:00
if ( ! access_ok ( VERIFY_WRITE , data , 33 * 8 ) )
return - EIO ;
if ( tsk_used_math ( child ) ) {
fpureg_t * fregs = get_fpu_regs ( child ) ;
for ( i = 0 ; i < 32 ; i + + )
2007-10-11 23:46:15 +01:00
__put_user ( fregs [ i ] , i + ( __u64 __user * ) data ) ;
2005-09-28 18:11:15 -04:00
} else {
for ( i = 0 ; i < 32 ; i + + )
2007-10-11 23:46:15 +01:00
__put_user ( ( __u64 ) - 1 , i + ( __u64 __user * ) data ) ;
2005-09-28 18:11:15 -04:00
}
2007-10-11 23:46:15 +01:00
__put_user ( child - > thread . fpu . fcr31 , data + 64 ) ;
2006-05-16 01:26:03 +09:00
2006-10-09 00:10:01 +09:00
preempt_disable ( ) ;
2005-09-28 18:11:15 -04:00
if ( cpu_has_fpu ) {
2006-10-09 00:10:01 +09:00
unsigned int flags ;
2005-09-28 18:11:15 -04:00
2005-10-06 17:39:32 +01:00
if ( cpu_has_mipsmt ) {
unsigned int vpflags = dvpe ( ) ;
flags = read_c0_status ( ) ;
__enable_fpu ( ) ;
__asm__ __volatile__ ( " cfc1 \t %0,$0 " : " =r " ( tmp ) ) ;
write_c0_status ( flags ) ;
evpe ( vpflags ) ;
} else {
flags = read_c0_status ( ) ;
__enable_fpu ( ) ;
__asm__ __volatile__ ( " cfc1 \t %0,$0 " : " =r " ( tmp ) ) ;
write_c0_status ( flags ) ;
}
2005-09-28 18:11:15 -04:00
} else {
2006-10-09 00:10:01 +09:00
tmp = 0 ;
2005-09-28 18:11:15 -04:00
}
2006-10-09 00:10:01 +09:00
preempt_enable ( ) ;
2007-10-11 23:46:15 +01:00
__put_user ( tmp , data + 65 ) ;
2005-09-28 18:11:15 -04:00
return 0 ;
}
2007-10-11 23:46:15 +01:00
int ptrace_setfpregs ( struct task_struct * child , __u32 __user * data )
2005-09-28 18:11:15 -04:00
{
fpureg_t * fregs ;
int i ;
if ( ! access_ok ( VERIFY_READ , data , 33 * 8 ) )
return - EIO ;
fregs = get_fpu_regs ( child ) ;
for ( i = 0 ; i < 32 ; i + + )
2007-10-11 23:46:15 +01:00
__get_user ( fregs [ i ] , i + ( __u64 __user * ) data ) ;
2005-09-28 18:11:15 -04:00
2007-10-11 23:46:15 +01:00
__get_user ( child - > thread . fpu . fcr31 , data + 64 ) ;
2005-09-28 18:11:15 -04:00
/* FIR may not be written. */
return 0 ;
}
2008-09-23 00:11:26 -07:00
int ptrace_get_watch_regs ( struct task_struct * child ,
struct pt_watch_regs __user * addr )
{
enum pt_watch_style style ;
int i ;
if ( ! cpu_has_watch | | current_cpu_data . watch_reg_use_cnt = = 0 )
return - EIO ;
if ( ! access_ok ( VERIFY_WRITE , addr , sizeof ( struct pt_watch_regs ) ) )
return - EIO ;
# ifdef CONFIG_32BIT
style = pt_watch_style_mips32 ;
# define WATCH_STYLE mips32
# else
style = pt_watch_style_mips64 ;
# define WATCH_STYLE mips64
# endif
__put_user ( style , & addr - > style ) ;
__put_user ( current_cpu_data . watch_reg_use_cnt ,
& addr - > WATCH_STYLE . num_valid ) ;
for ( i = 0 ; i < current_cpu_data . watch_reg_use_cnt ; i + + ) {
__put_user ( child - > thread . watch . mips3264 . watchlo [ i ] ,
& addr - > WATCH_STYLE . watchlo [ i ] ) ;
__put_user ( child - > thread . watch . mips3264 . watchhi [ i ] & 0xfff ,
& addr - > WATCH_STYLE . watchhi [ i ] ) ;
__put_user ( current_cpu_data . watch_reg_masks [ i ] ,
& addr - > WATCH_STYLE . watch_masks [ i ] ) ;
}
for ( ; i < 8 ; i + + ) {
__put_user ( 0 , & addr - > WATCH_STYLE . watchlo [ i ] ) ;
__put_user ( 0 , & addr - > WATCH_STYLE . watchhi [ i ] ) ;
__put_user ( 0 , & addr - > WATCH_STYLE . watch_masks [ i ] ) ;
}
return 0 ;
}
int ptrace_set_watch_regs ( struct task_struct * child ,
struct pt_watch_regs __user * addr )
{
int i ;
int watch_active = 0 ;
unsigned long lt [ NUM_WATCH_REGS ] ;
u16 ht [ NUM_WATCH_REGS ] ;
if ( ! cpu_has_watch | | current_cpu_data . watch_reg_use_cnt = = 0 )
return - EIO ;
if ( ! access_ok ( VERIFY_READ , addr , sizeof ( struct pt_watch_regs ) ) )
return - EIO ;
/* Check the values. */
for ( i = 0 ; i < current_cpu_data . watch_reg_use_cnt ; i + + ) {
__get_user ( lt [ i ] , & addr - > WATCH_STYLE . watchlo [ i ] ) ;
# ifdef CONFIG_32BIT
if ( lt [ i ] & __UA_LIMIT )
return - EINVAL ;
# else
if ( test_tsk_thread_flag ( child , TIF_32BIT_ADDR ) ) {
if ( lt [ i ] & 0xffffffff80000000UL )
return - EINVAL ;
} else {
if ( lt [ i ] & __UA_LIMIT )
return - EINVAL ;
}
# endif
__get_user ( ht [ i ] , & addr - > WATCH_STYLE . watchhi [ i ] ) ;
if ( ht [ i ] & ~ 0xff8 )
return - EINVAL ;
}
/* Install them. */
for ( i = 0 ; i < current_cpu_data . watch_reg_use_cnt ; i + + ) {
if ( lt [ i ] & 7 )
watch_active = 1 ;
child - > thread . watch . mips3264 . watchlo [ i ] = lt [ i ] ;
/* Set the G bit. */
child - > thread . watch . mips3264 . watchhi [ i ] = ht [ i ] ;
}
if ( watch_active )
set_tsk_thread_flag ( child , TIF_LOAD_WATCH ) ;
else
clear_tsk_thread_flag ( child , TIF_LOAD_WATCH ) ;
return 0 ;
}
2010-10-27 15:33:47 -07:00
long arch_ptrace ( struct task_struct * child , long request ,
unsigned long addr , unsigned long data )
2005-04-16 15:20:36 -07:00
{
int ret ;
2010-10-27 15:33:58 -07:00
void __user * addrp = ( void __user * ) addr ;
void __user * datavp = ( void __user * ) data ;
unsigned long __user * datalp = ( void __user * ) data ;
2005-04-16 15:20:36 -07:00
switch ( request ) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT : /* read word at location addr. */
2007-07-17 04:03:43 -07:00
case PTRACE_PEEKDATA :
ret = generic_ptrace_peekdata ( child , addr , data ) ;
2005-04-16 15:20:36 -07:00
break ;
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR : {
struct pt_regs * regs ;
unsigned long tmp = 0 ;
2006-01-12 01:06:07 -08:00
regs = task_pt_regs ( child ) ;
2005-04-16 15:20:36 -07:00
ret = 0 ; /* Default return value. */
switch ( addr ) {
case 0 . . . 31 :
tmp = regs - > regs [ addr ] ;
break ;
case FPR_BASE . . . FPR_BASE + 31 :
if ( tsk_used_math ( child ) ) {
fpureg_t * fregs = get_fpu_regs ( child ) ;
2005-09-03 15:56:16 -07:00
# ifdef CONFIG_32BIT
2005-04-16 15:20:36 -07:00
/*
* The odd registers are actually the high
* order bits of the values stored in the even
* registers - unless we ' re using r2k_switch . S .
*/
if ( addr & 1 )
tmp = ( unsigned long ) ( fregs [ ( ( addr & ~ 1 ) - 32 ) ] > > 32 ) ;
else
tmp = ( unsigned long ) ( fregs [ ( addr - 32 ) ] & 0xffffffff ) ;
# endif
2005-09-03 15:56:16 -07:00
# ifdef CONFIG_64BIT
2005-04-16 15:20:36 -07:00
tmp = fregs [ addr - FPR_BASE ] ;
# endif
} else {
tmp = - 1 ; /* FP not yet used */
}
break ;
case PC :
tmp = regs - > cp0_epc ;
break ;
case CAUSE :
tmp = regs - > cp0_cause ;
break ;
case BADVADDR :
tmp = regs - > cp0_badvaddr ;
break ;
case MMHI :
tmp = regs - > hi ;
break ;
case MMLO :
tmp = regs - > lo ;
break ;
2007-02-02 17:41:47 +01:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
case ACX :
tmp = regs - > acx ;
break ;
# endif
2005-04-16 15:20:36 -07:00
case FPC_CSR :
2006-05-16 01:26:03 +09:00
tmp = child - > thread . fpu . fcr31 ;
2005-04-16 15:20:36 -07:00
break ;
case FPC_EIR : { /* implementation / version register */
unsigned int flags ;
2006-04-05 09:45:45 +01:00
# ifdef CONFIG_MIPS_MT_SMTC
2008-10-01 21:52:41 +01:00
unsigned long irqflags ;
2006-04-05 09:45:45 +01:00
unsigned int mtflags ;
# endif /* CONFIG_MIPS_MT_SMTC */
2005-04-16 15:20:36 -07:00
2006-10-09 00:10:01 +09:00
preempt_disable ( ) ;
if ( ! cpu_has_fpu ) {
preempt_enable ( ) ;
2005-04-16 15:20:36 -07:00
break ;
2006-10-09 00:10:01 +09:00
}
2005-04-16 15:20:36 -07:00
2006-04-05 09:45:45 +01:00
# ifdef CONFIG_MIPS_MT_SMTC
/* Read-modify-write of Status must be atomic */
local_irq_save ( irqflags ) ;
mtflags = dmt ( ) ;
# endif /* CONFIG_MIPS_MT_SMTC */
2005-10-06 17:39:32 +01:00
if ( cpu_has_mipsmt ) {
unsigned int vpflags = dvpe ( ) ;
flags = read_c0_status ( ) ;
__enable_fpu ( ) ;
__asm__ __volatile__ ( " cfc1 \t %0,$0 " : " =r " ( tmp ) ) ;
write_c0_status ( flags ) ;
evpe ( vpflags ) ;
} else {
flags = read_c0_status ( ) ;
__enable_fpu ( ) ;
__asm__ __volatile__ ( " cfc1 \t %0,$0 " : " =r " ( tmp ) ) ;
write_c0_status ( flags ) ;
}
2006-04-05 09:45:45 +01:00
# ifdef CONFIG_MIPS_MT_SMTC
emt ( mtflags ) ;
local_irq_restore ( irqflags ) ;
# endif /* CONFIG_MIPS_MT_SMTC */
2005-10-06 17:39:32 +01:00
preempt_enable ( ) ;
2005-04-16 15:20:36 -07:00
break ;
}
2005-06-30 09:42:00 +00:00
case DSP_BASE . . . DSP_BASE + 5 : {
dspreg_t * dregs ;
2005-05-31 11:49:19 +00:00
if ( ! cpu_has_dsp ) {
tmp = 0 ;
ret = - EIO ;
2005-11-07 00:59:47 -08:00
goto out ;
2005-05-31 11:49:19 +00:00
}
2005-12-05 13:47:25 +00:00
dregs = __get_dsp_regs ( child ) ;
tmp = ( unsigned long ) ( dregs [ addr - DSP_BASE ] ) ;
2005-05-31 11:49:19 +00:00
break ;
2005-06-30 09:42:00 +00:00
}
2005-05-31 11:49:19 +00:00
case DSP_CONTROL :
if ( ! cpu_has_dsp ) {
tmp = 0 ;
ret = - EIO ;
2005-11-07 00:59:47 -08:00
goto out ;
2005-05-31 11:49:19 +00:00
}
tmp = child - > thread . dsp . dspcontrol ;
break ;
2005-04-16 15:20:36 -07:00
default :
tmp = 0 ;
ret = - EIO ;
2005-11-07 00:59:47 -08:00
goto out ;
2005-04-16 15:20:36 -07:00
}
2010-10-27 15:33:58 -07:00
ret = put_user ( tmp , datalp ) ;
2005-04-16 15:20:36 -07:00
break ;
}
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT : /* write the word at location addr. */
case PTRACE_POKEDATA :
2007-07-17 04:03:44 -07:00
ret = generic_ptrace_pokedata ( child , addr , data ) ;
2005-04-16 15:20:36 -07:00
break ;
case PTRACE_POKEUSR : {
struct pt_regs * regs ;
ret = 0 ;
2006-01-12 01:06:07 -08:00
regs = task_pt_regs ( child ) ;
2005-04-16 15:20:36 -07:00
switch ( addr ) {
case 0 . . . 31 :
regs - > regs [ addr ] = data ;
break ;
case FPR_BASE . . . FPR_BASE + 31 : {
fpureg_t * fregs = get_fpu_regs ( child ) ;
if ( ! tsk_used_math ( child ) ) {
/* FP not yet used */
2006-05-16 01:26:03 +09:00
memset ( & child - > thread . fpu , ~ 0 ,
sizeof ( child - > thread . fpu ) ) ;
child - > thread . fpu . fcr31 = 0 ;
2005-04-16 15:20:36 -07:00
}
2005-09-03 15:56:16 -07:00
# ifdef CONFIG_32BIT
2005-04-16 15:20:36 -07:00
/*
* The odd registers are actually the high order bits
* of the values stored in the even registers - unless
* we ' re using r2k_switch . S .
*/
if ( addr & 1 ) {
fregs [ ( addr & ~ 1 ) - FPR_BASE ] & = 0xffffffff ;
fregs [ ( addr & ~ 1 ) - FPR_BASE ] | = ( ( unsigned long long ) data ) < < 32 ;
} else {
fregs [ addr - FPR_BASE ] & = ~ 0xffffffffLL ;
fregs [ addr - FPR_BASE ] | = data ;
}
# endif
2005-09-03 15:56:16 -07:00
# ifdef CONFIG_64BIT
2005-04-16 15:20:36 -07:00
fregs [ addr - FPR_BASE ] = data ;
# endif
break ;
}
case PC :
regs - > cp0_epc = data ;
break ;
case MMHI :
regs - > hi = data ;
break ;
case MMLO :
regs - > lo = data ;
break ;
2007-02-02 17:41:47 +01:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
case ACX :
regs - > acx = data ;
break ;
# endif
2005-04-16 15:20:36 -07:00
case FPC_CSR :
2006-05-16 01:26:03 +09:00
child - > thread . fpu . fcr31 = data ;
2005-04-16 15:20:36 -07:00
break ;
2005-06-30 09:42:00 +00:00
case DSP_BASE . . . DSP_BASE + 5 : {
dspreg_t * dregs ;
2005-05-31 11:49:19 +00:00
if ( ! cpu_has_dsp ) {
ret = - EIO ;
break ;
}
2005-06-30 09:42:00 +00:00
dregs = __get_dsp_regs ( child ) ;
2005-05-31 11:49:19 +00:00
dregs [ addr - DSP_BASE ] = data ;
break ;
2005-06-30 09:42:00 +00:00
}
2005-05-31 11:49:19 +00:00
case DSP_CONTROL :
if ( ! cpu_has_dsp ) {
ret = - EIO ;
break ;
}
child - > thread . dsp . dspcontrol = data ;
break ;
2005-04-16 15:20:36 -07:00
default :
/* The rest are not allowed. */
ret = - EIO ;
break ;
}
break ;
}
2005-09-28 18:11:15 -04:00
case PTRACE_GETREGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_getregs ( child , datavp ) ;
2005-09-28 18:11:15 -04:00
break ;
case PTRACE_SETREGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_setregs ( child , datavp ) ;
2005-09-28 18:11:15 -04:00
break ;
case PTRACE_GETFPREGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_getfpregs ( child , datavp ) ;
2005-09-28 18:11:15 -04:00
break ;
case PTRACE_SETFPREGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_setfpregs ( child , datavp ) ;
2005-09-28 18:11:15 -04:00
break ;
2005-04-13 17:43:59 +00:00
case PTRACE_GET_THREAD_AREA :
2010-10-27 15:33:58 -07:00
ret = put_user ( task_thread_info ( child ) - > tp_value , datalp ) ;
2005-04-13 17:43:59 +00:00
break ;
2008-09-23 00:11:26 -07:00
case PTRACE_GET_WATCH_REGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_get_watch_regs ( child , addrp ) ;
2008-09-23 00:11:26 -07:00
break ;
case PTRACE_SET_WATCH_REGS :
2010-10-27 15:33:58 -07:00
ret = ptrace_set_watch_regs ( child , addrp ) ;
2008-09-23 00:11:26 -07:00
break ;
2005-04-16 15:20:36 -07:00
default :
ret = ptrace_request ( child , request , addr , data ) ;
break ;
}
2005-11-07 00:59:47 -08:00
out :
2005-04-16 15:20:36 -07:00
return ret ;
}
2005-04-29 16:13:35 +01:00
static inline int audit_arch ( void )
2005-04-29 16:08:28 +01:00
{
2005-05-19 12:08:04 +00:00
int arch = EM_MIPS ;
2005-09-03 15:56:16 -07:00
# ifdef CONFIG_64BIT
2005-05-19 12:08:04 +00:00
arch | = __AUDIT_ARCH_64BIT ;
# endif
# if defined(__LITTLE_ENDIAN)
arch | = __AUDIT_ARCH_LE ;
# endif
return arch ;
2005-04-29 16:08:28 +01:00
}
2005-04-16 15:20:36 -07:00
/*
* Notification of system call entry / exit
* - triggered by current - > work . syscall_trace
*/
2011-05-19 09:21:29 +01:00
asmlinkage void syscall_trace_enter ( struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2007-07-25 16:19:33 +01:00
/* do the secure computing check first */
2011-05-19 09:21:29 +01:00
secure_computing ( regs - > regs [ 2 ] ) ;
2005-04-16 15:20:36 -07:00
if ( ! ( current - > ptrace & PT_PTRACED ) )
2005-04-29 16:08:28 +01:00
goto out ;
2007-07-25 16:19:33 +01:00
2005-05-19 12:08:04 +00:00
if ( ! test_thread_flag ( TIF_SYSCALL_TRACE ) )
goto out ;
2005-04-16 15:20:36 -07:00
/* The 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
ptrace_notify ( SIGTRAP | ( ( current - > ptrace & PT_TRACESYSGOOD ) ?
0x80 : 0 ) ) ;
/*
* this isn ' t the same as continuing with a signal , but it will do
* for normal use . strace only continues with a signal if the
* stopping signal is not SIGTRAP . - brl
*/
if ( current - > exit_code ) {
send_sig ( current - > exit_code , current , 1 ) ;
current - > exit_code = 0 ;
}
2007-07-25 16:19:33 +01:00
out :
2011-05-19 09:21:29 +01:00
if ( unlikely ( current - > audit_context ) )
2010-09-28 18:50:27 +01:00
audit_syscall_entry ( audit_arch ( ) , regs - > regs [ 2 ] ,
2005-04-29 16:08:28 +01:00
regs - > regs [ 4 ] , regs - > regs [ 5 ] ,
regs - > regs [ 6 ] , regs - > regs [ 7 ] ) ;
2005-04-16 15:20:36 -07:00
}
2011-05-19 09:21:29 +01:00
/*
* Notification of system call entry / exit
* - triggered by current - > work . syscall_trace
*/
asmlinkage void syscall_trace_leave ( struct pt_regs * regs )
{
if ( unlikely ( current - > audit_context ) )
audit_syscall_exit ( AUDITSC_RESULT ( regs - > regs [ 7 ] ) ,
- regs - > regs [ 2 ] ) ;
if ( ! ( current - > ptrace & PT_PTRACED ) )
return ;
if ( ! test_thread_flag ( TIF_SYSCALL_TRACE ) )
return ;
/* The 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
ptrace_notify ( SIGTRAP | ( ( current - > ptrace & PT_TRACESYSGOOD ) ?
0x80 : 0 ) ) ;
/*
* this isn ' t the same as continuing with a signal , but it will do
* for normal use . strace only continues with a signal if the
* stopping signal is not SIGTRAP . - brl
*/
if ( current - > exit_code ) {
send_sig ( current - > exit_code , current , 1 ) ;
current - > exit_code = 0 ;
}
}