2005-04-17 02:20:36 +04: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>
2013-05-29 03:07:19 +04:00
# include <linux/context_tracking.h>
2012-08-02 16:44:11 +04:00
# include <linux/elf.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/errno.h>
# include <linux/ptrace.h>
2012-08-02 16:44:11 +04:00
# include <linux/regset.h>
2005-04-17 02:20:36 +04:00
# include <linux/smp.h>
# include <linux/user.h>
# include <linux/security.h>
2012-07-17 21:43:58 +04:00
# include <linux/tracehook.h>
2007-07-25 19:19:33 +04:00
# include <linux/audit.h>
# include <linux/seccomp.h>
2013-09-06 22:24:48 +04:00
# include <linux/ftrace.h>
2005-04-17 02:20:36 +04:00
2005-05-19 16:08:04 +04:00
# include <asm/byteorder.h>
2005-04-17 02:20:36 +04:00
# include <asm/cpu.h>
2005-05-31 15:49:19 +04:00
# include <asm/dsp.h>
2005-04-17 02:20:36 +04:00
# include <asm/fpu.h>
# include <asm/mipsregs.h>
2005-10-06 20:39:32 +04:00
# include <asm/mipsmtregs.h>
2005-04-17 02:20:36 +04:00
# include <asm/pgtable.h>
# include <asm/page.h>
2012-09-26 22:16:47 +04:00
# include <asm/syscall.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/bootinfo.h>
2005-09-29 02:11:15 +04:00
# include <asm/reg.h>
2005-04-17 02:20:36 +04:00
2013-09-06 22:24:48 +04:00
# define CREATE_TRACE_POINTS
# include <trace/events/syscalls.h>
2005-04-17 02:20:36 +04: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 11:11:26 +04:00
/* Don't load the watchpoint registers for the ex-child. */
clear_tsk_thread_flag ( child , TIF_LOAD_WATCH ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-29 02:11:15 +04:00
/*
2013-01-22 15:59:30 +04:00
* Read a general register set . We always use the 64 - bit format , even
2005-09-29 02:11:15 +04:00
* 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-12 02:46:15 +04:00
int ptrace_getregs ( struct task_struct * child , __s64 __user * data )
2005-09-29 02:11:15 +04:00
{
struct pt_regs * regs ;
int i ;
if ( ! access_ok ( VERIFY_WRITE , data , 38 * 8 ) )
return - EIO ;
2006-01-12 12:06:07 +03:00
regs = task_pt_regs ( child ) ;
2005-09-29 02:11:15 +04:00
for ( i = 0 ; i < 32 ; i + + )
2007-10-25 19:53:02 +04: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-29 02: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-12 02:46:15 +04:00
int ptrace_setregs ( struct task_struct * child , __s64 __user * data )
2005-09-29 02:11:15 +04:00
{
struct pt_regs * regs ;
int i ;
if ( ! access_ok ( VERIFY_READ , data , 38 * 8 ) )
return - EIO ;
2006-01-12 12:06:07 +03:00
regs = task_pt_regs ( child ) ;
2005-09-29 02:11:15 +04:00
for ( i = 0 ; i < 32 ; i + + )
2007-10-12 02:46:15 +04: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-29 02:11:15 +04:00
/* badvaddr, status, and cause may not be written. */
return 0 ;
}
2007-10-12 02:46:15 +04:00
int ptrace_getfpregs ( struct task_struct * child , __u32 __user * data )
2005-09-29 02:11:15 +04:00
{
int i ;
if ( ! access_ok ( VERIFY_WRITE , data , 33 * 8 ) )
return - EIO ;
if ( tsk_used_math ( child ) ) {
2014-02-13 15:26:41 +04:00
union fpureg * fregs = get_fpu_regs ( child ) ;
2005-09-29 02:11:15 +04:00
for ( i = 0 ; i < 32 ; i + + )
2014-02-13 15:26:41 +04:00
__put_user ( get_fpr64 ( & fregs [ i ] , 0 ) ,
i + ( __u64 __user * ) data ) ;
2005-09-29 02:11:15 +04:00
} else {
for ( i = 0 ; i < 32 ; i + + )
2007-10-12 02:46:15 +04:00
__put_user ( ( __u64 ) - 1 , i + ( __u64 __user * ) data ) ;
2005-09-29 02:11:15 +04:00
}
2007-10-12 02:46:15 +04:00
__put_user ( child - > thread . fpu . fcr31 , data + 64 ) ;
2013-11-19 21:30:36 +04:00
__put_user ( current_cpu_data . fpu_id , data + 65 ) ;
2005-09-29 02:11:15 +04:00
return 0 ;
}
2007-10-12 02:46:15 +04:00
int ptrace_setfpregs ( struct task_struct * child , __u32 __user * data )
2005-09-29 02:11:15 +04:00
{
2014-02-13 15:26:41 +04:00
union fpureg * fregs ;
u64 fpr_val ;
2005-09-29 02:11:15 +04:00
int i ;
if ( ! access_ok ( VERIFY_READ , data , 33 * 8 ) )
return - EIO ;
fregs = get_fpu_regs ( child ) ;
2014-02-13 15:26:41 +04:00
for ( i = 0 ; i < 32 ; i + + ) {
__get_user ( fpr_val , i + ( __u64 __user * ) data ) ;
set_fpr64 ( & fregs [ i ] , 0 , fpr_val ) ;
}
2005-09-29 02:11:15 +04:00
2007-10-12 02:46:15 +04:00
__get_user ( child - > thread . fpu . fcr31 , data + 64 ) ;
2005-09-29 02:11:15 +04:00
/* FIR may not be written. */
return 0 ;
}
2008-09-23 11:11:26 +04: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 ;
}
2012-08-02 16:44:11 +04:00
/* regset get/set implementations */
static int gpr_get ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
void * kbuf , void __user * ubuf )
{
struct pt_regs * regs = task_pt_regs ( target ) ;
return user_regset_copyout ( & pos , & count , & kbuf , & ubuf ,
regs , 0 , sizeof ( * regs ) ) ;
}
static int gpr_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
struct pt_regs newregs ;
int ret ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
& newregs ,
0 , sizeof ( newregs ) ) ;
if ( ret )
return ret ;
* task_pt_regs ( target ) = newregs ;
return 0 ;
}
static int fpr_get ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
void * kbuf , void __user * ubuf )
{
2014-01-27 19:23:07 +04:00
unsigned i ;
int err ;
u64 fpr_val ;
2012-08-02 16:44:11 +04:00
/* XXX fcr31 */
2014-01-27 19:23:07 +04:00
if ( sizeof ( target - > thread . fpu . fpr [ i ] ) = = sizeof ( elf_fpreg_t ) )
return user_regset_copyout ( & pos , & count , & kbuf , & ubuf ,
& target - > thread . fpu ,
0 , sizeof ( elf_fpregset_t ) ) ;
for ( i = 0 ; i < NUM_FPU_REGS ; i + + ) {
fpr_val = get_fpr64 ( & target - > thread . fpu . fpr [ i ] , 0 ) ;
err = user_regset_copyout ( & pos , & count , & kbuf , & ubuf ,
& fpr_val , i * sizeof ( elf_fpreg_t ) ,
( i + 1 ) * sizeof ( elf_fpreg_t ) ) ;
if ( err )
return err ;
}
return 0 ;
2012-08-02 16:44:11 +04:00
}
static int fpr_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
2014-01-27 19:23:07 +04:00
unsigned i ;
int err ;
u64 fpr_val ;
2012-08-02 16:44:11 +04:00
/* XXX fcr31 */
2014-01-27 19:23:07 +04:00
if ( sizeof ( target - > thread . fpu . fpr [ i ] ) = = sizeof ( elf_fpreg_t ) )
return user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
& target - > thread . fpu ,
0 , sizeof ( elf_fpregset_t ) ) ;
for ( i = 0 ; i < NUM_FPU_REGS ; i + + ) {
err = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
& fpr_val , i * sizeof ( elf_fpreg_t ) ,
( i + 1 ) * sizeof ( elf_fpreg_t ) ) ;
if ( err )
return err ;
set_fpr64 ( & target - > thread . fpu . fpr [ i ] , 0 , fpr_val ) ;
}
return 0 ;
2012-08-02 16:44:11 +04:00
}
enum mips_regset {
REGSET_GPR ,
REGSET_FPR ,
} ;
static const struct user_regset mips_regsets [ ] = {
[ REGSET_GPR ] = {
. core_note_type = NT_PRSTATUS ,
. n = ELF_NGREG ,
. size = sizeof ( unsigned int ) ,
. align = sizeof ( unsigned int ) ,
. get = gpr_get ,
. set = gpr_set ,
} ,
[ REGSET_FPR ] = {
. core_note_type = NT_PRFPREG ,
. n = ELF_NFPREG ,
. size = sizeof ( elf_fpreg_t ) ,
. align = sizeof ( elf_fpreg_t ) ,
. get = fpr_get ,
. set = fpr_set ,
} ,
} ;
static const struct user_regset_view user_mips_view = {
. name = " mips " ,
. e_machine = ELF_ARCH ,
. ei_osabi = ELF_OSABI ,
. regsets = mips_regsets ,
. n = ARRAY_SIZE ( mips_regsets ) ,
} ;
static const struct user_regset mips64_regsets [ ] = {
[ REGSET_GPR ] = {
. core_note_type = NT_PRSTATUS ,
. n = ELF_NGREG ,
. size = sizeof ( unsigned long ) ,
. align = sizeof ( unsigned long ) ,
. get = gpr_get ,
. set = gpr_set ,
} ,
[ REGSET_FPR ] = {
. core_note_type = NT_PRFPREG ,
. n = ELF_NFPREG ,
. size = sizeof ( elf_fpreg_t ) ,
. align = sizeof ( elf_fpreg_t ) ,
. get = fpr_get ,
. set = fpr_set ,
} ,
} ;
static const struct user_regset_view user_mips64_view = {
. name = " mips " ,
. e_machine = ELF_ARCH ,
. ei_osabi = ELF_OSABI ,
. regsets = mips64_regsets ,
. n = ARRAY_SIZE ( mips_regsets ) ,
} ;
const struct user_regset_view * task_user_regset_view ( struct task_struct * task )
{
# ifdef CONFIG_32BIT
return & user_mips_view ;
# endif
# ifdef CONFIG_MIPS32_O32
if ( test_thread_flag ( TIF_32BIT_REGS ) )
return & user_mips_view ;
# endif
return & user_mips64_view ;
}
2010-10-28 02:33:47 +04:00
long arch_ptrace ( struct task_struct * child , long request ,
unsigned long addr , unsigned long data )
2005-04-17 02:20:36 +04:00
{
int ret ;
2010-10-28 02:33:58 +04:00
void __user * addrp = ( void __user * ) addr ;
void __user * datavp = ( void __user * ) data ;
unsigned long __user * datalp = ( void __user * ) data ;
2005-04-17 02:20:36 +04: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 15:03:43 +04:00
case PTRACE_PEEKDATA :
ret = generic_ptrace_peekdata ( child , addr , data ) ;
2005-04-17 02:20:36 +04:00
break ;
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR : {
struct pt_regs * regs ;
2014-02-13 15:26:41 +04:00
union fpureg * fregs ;
2005-04-17 02:20:36 +04:00
unsigned long tmp = 0 ;
2006-01-12 12:06:07 +03:00
regs = task_pt_regs ( child ) ;
2005-04-17 02:20:36 +04:00
ret = 0 ; /* Default return value. */
switch ( addr ) {
case 0 . . . 31 :
tmp = regs - > regs [ addr ] ;
break ;
case FPR_BASE . . . FPR_BASE + 31 :
2013-11-22 17:12:07 +04:00
if ( ! tsk_used_math ( child ) ) {
/* FP not yet used */
tmp = - 1 ;
break ;
}
fregs = get_fpu_regs ( child ) ;
2005-04-17 02:20:36 +04:00
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_32BIT
2013-11-22 17:12:07 +04:00
if ( test_thread_flag ( TIF_32BIT_FPREGS ) ) {
2005-04-17 02:20:36 +04: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 .
*/
2014-02-13 15:26:41 +04:00
tmp = get_fpr32 ( & fregs [ ( addr & ~ 1 ) - FPR_BASE ] ,
addr & 1 ) ;
2013-11-22 17:12:07 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2013-11-22 17:12:07 +04:00
# endif
2014-02-13 15:26:41 +04:00
tmp = get_fpr32 ( & fregs [ addr - FPR_BASE ] , 0 ) ;
2005-04-17 02:20:36 +04:00
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 19:41:47 +03:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
case ACX :
tmp = regs - > acx ;
break ;
# endif
2005-04-17 02:20:36 +04:00
case FPC_CSR :
2006-05-15 20:26:03 +04:00
tmp = child - > thread . fpu . fcr31 ;
2005-04-17 02:20:36 +04:00
break ;
2013-11-19 21:30:35 +04:00
case FPC_EIR :
/* implementation / version register */
tmp = current_cpu_data . fpu_id ;
2005-04-17 02:20:36 +04:00
break ;
2005-06-30 13:42:00 +04:00
case DSP_BASE . . . DSP_BASE + 5 : {
dspreg_t * dregs ;
2005-05-31 15:49:19 +04:00
if ( ! cpu_has_dsp ) {
tmp = 0 ;
ret = - EIO ;
2005-11-07 11:59:47 +03:00
goto out ;
2005-05-31 15:49:19 +04:00
}
2005-12-05 16:47:25 +03:00
dregs = __get_dsp_regs ( child ) ;
tmp = ( unsigned long ) ( dregs [ addr - DSP_BASE ] ) ;
2005-05-31 15:49:19 +04:00
break ;
2005-06-30 13:42:00 +04:00
}
2005-05-31 15:49:19 +04:00
case DSP_CONTROL :
if ( ! cpu_has_dsp ) {
tmp = 0 ;
ret = - EIO ;
2005-11-07 11:59:47 +03:00
goto out ;
2005-05-31 15:49:19 +04:00
}
tmp = child - > thread . dsp . dspcontrol ;
break ;
2005-04-17 02:20:36 +04:00
default :
tmp = 0 ;
ret = - EIO ;
2005-11-07 11:59:47 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2010-10-28 02:33:58 +04:00
ret = put_user ( tmp , datalp ) ;
2005-04-17 02:20:36 +04: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 15:03:44 +04:00
ret = generic_ptrace_pokedata ( child , addr , data ) ;
2005-04-17 02:20:36 +04:00
break ;
case PTRACE_POKEUSR : {
struct pt_regs * regs ;
ret = 0 ;
2006-01-12 12:06:07 +03:00
regs = task_pt_regs ( child ) ;
2005-04-17 02:20:36 +04:00
switch ( addr ) {
case 0 . . . 31 :
regs - > regs [ addr ] = data ;
break ;
case FPR_BASE . . . FPR_BASE + 31 : {
2014-02-13 15:26:41 +04:00
union fpureg * fregs = get_fpu_regs ( child ) ;
2005-04-17 02:20:36 +04:00
if ( ! tsk_used_math ( child ) ) {
/* FP not yet used */
2006-05-15 20:26:03 +04:00
memset ( & child - > thread . fpu , ~ 0 ,
sizeof ( child - > thread . fpu ) ) ;
child - > thread . fpu . fcr31 = 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_32BIT
2013-11-22 17:12:07 +04:00
if ( test_thread_flag ( TIF_32BIT_FPREGS ) ) {
/*
* The odd registers are actually the high
* order bits of the values stored in the even
* registers - unless we ' re using r2k_switch . S .
*/
2014-02-13 15:26:41 +04:00
set_fpr32 ( & fregs [ ( addr & ~ 1 ) - FPR_BASE ] ,
addr & 1 , data ) ;
2013-11-22 17:12:07 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
# endif
2014-02-13 15:26:41 +04:00
set_fpr64 ( & fregs [ addr - FPR_BASE ] , 0 , data ) ;
2005-04-17 02:20:36 +04:00
break ;
}
case PC :
regs - > cp0_epc = data ;
break ;
case MMHI :
regs - > hi = data ;
break ;
case MMLO :
regs - > lo = data ;
break ;
2007-02-02 19:41:47 +03:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
case ACX :
regs - > acx = data ;
break ;
# endif
2005-04-17 02:20:36 +04:00
case FPC_CSR :
2006-05-15 20:26:03 +04:00
child - > thread . fpu . fcr31 = data ;
2005-04-17 02:20:36 +04:00
break ;
2005-06-30 13:42:00 +04:00
case DSP_BASE . . . DSP_BASE + 5 : {
dspreg_t * dregs ;
2005-05-31 15:49:19 +04:00
if ( ! cpu_has_dsp ) {
ret = - EIO ;
break ;
}
2005-06-30 13:42:00 +04:00
dregs = __get_dsp_regs ( child ) ;
2005-05-31 15:49:19 +04:00
dregs [ addr - DSP_BASE ] = data ;
break ;
2005-06-30 13:42:00 +04:00
}
2005-05-31 15:49:19 +04:00
case DSP_CONTROL :
if ( ! cpu_has_dsp ) {
ret = - EIO ;
break ;
}
child - > thread . dsp . dspcontrol = data ;
break ;
2005-04-17 02:20:36 +04:00
default :
/* The rest are not allowed. */
ret = - EIO ;
break ;
}
break ;
}
2005-09-29 02:11:15 +04:00
case PTRACE_GETREGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_getregs ( child , datavp ) ;
2005-09-29 02:11:15 +04:00
break ;
case PTRACE_SETREGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_setregs ( child , datavp ) ;
2005-09-29 02:11:15 +04:00
break ;
case PTRACE_GETFPREGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_getfpregs ( child , datavp ) ;
2005-09-29 02:11:15 +04:00
break ;
case PTRACE_SETFPREGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_setfpregs ( child , datavp ) ;
2005-09-29 02:11:15 +04:00
break ;
2005-04-13 21:43:59 +04:00
case PTRACE_GET_THREAD_AREA :
2010-10-28 02:33:58 +04:00
ret = put_user ( task_thread_info ( child ) - > tp_value , datalp ) ;
2005-04-13 21:43:59 +04:00
break ;
2008-09-23 11:11:26 +04:00
case PTRACE_GET_WATCH_REGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_get_watch_regs ( child , addrp ) ;
2008-09-23 11:11:26 +04:00
break ;
case PTRACE_SET_WATCH_REGS :
2010-10-28 02:33:58 +04:00
ret = ptrace_set_watch_regs ( child , addrp ) ;
2008-09-23 11:11:26 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
ret = ptrace_request ( child , request , addr , data ) ;
break ;
}
2005-11-07 11:59:47 +03:00
out :
2005-04-17 02:20:36 +04:00
return ret ;
}
/*
* Notification of system call entry / exit
* - triggered by current - > work . syscall_trace
*/
2014-01-22 18:40:03 +04:00
asmlinkage long syscall_trace_enter ( struct pt_regs * regs , long syscall )
2005-04-17 02:20:36 +04:00
{
2012-09-26 23:30:47 +04:00
long ret = 0 ;
2013-05-29 03:07:19 +04:00
user_exit ( ) ;
2014-01-22 18:40:01 +04:00
if ( secure_computing ( syscall ) = = - 1 )
return - 1 ;
2005-04-17 02:20:36 +04:00
2012-09-26 23:30:47 +04:00
if ( test_thread_flag ( TIF_SYSCALL_TRACE ) & &
tracehook_report_syscall_entry ( regs ) )
ret = - 1 ;
2007-07-25 19:19:33 +04:00
2013-09-06 22:24:48 +04:00
if ( unlikely ( test_thread_flag ( TIF_SYSCALL_TRACEPOINT ) ) )
trace_sys_enter ( regs , regs - > regs [ 2 ] ) ;
2014-01-22 18:39:59 +04:00
audit_syscall_entry ( syscall_get_arch ( current , regs ) ,
2014-01-22 18:40:01 +04:00
syscall ,
2012-01-03 23:23:06 +04:00
regs - > regs [ 4 ] , regs - > regs [ 5 ] ,
regs - > regs [ 6 ] , regs - > regs [ 7 ] ) ;
2014-01-22 18:40:01 +04:00
return syscall ;
2005-04-17 02:20:36 +04:00
}
2011-05-19 12:21:29 +04:00
/*
* Notification of system call entry / exit
* - triggered by current - > work . syscall_trace
*/
asmlinkage void syscall_trace_leave ( struct pt_regs * regs )
{
2013-05-29 03:07:19 +04:00
/*
* We may come here right after calling schedule_user ( )
* or do_notify_resume ( ) , in which case we can be in RCU
* user mode .
*/
user_exit ( ) ;
2012-01-03 23:23:06 +04:00
audit_syscall_exit ( regs ) ;
2011-05-19 12:21:29 +04:00
2013-09-06 22:24:48 +04:00
if ( unlikely ( test_thread_flag ( TIF_SYSCALL_TRACEPOINT ) ) )
trace_sys_exit ( regs , regs - > regs [ 2 ] ) ;
2012-07-17 21:43:58 +04:00
if ( test_thread_flag ( TIF_SYSCALL_TRACE ) )
tracehook_report_syscall_exit ( regs , 0 ) ;
2013-05-29 03:07:19 +04:00
user_enter ( ) ;
2011-05-19 12:21:29 +04:00
}