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>
2017-02-08 20:51:37 +03:00
# include <linux/sched/task_stack.h>
2005-04-17 02:20:36 +04:00
# 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/security.h>
2015-07-29 23:44:53 +03:00
# include <linux/stddef.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>
2015-04-04 01:27:48 +03:00
# include <asm/cpu-info.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>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# 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>
2015-01-30 15:09:36 +03:00
static void init_fp_ctx ( struct task_struct * target )
{
/* If FP has been used then the target already has context */
if ( tsk_used_math ( target ) )
return ;
/* Begin with data registers set to all 1s... */
memset ( & target - > thread . fpu . fpr , ~ 0 , sizeof ( target - > thread . fpu . fpr ) ) ;
2016-05-12 12:19:08 +03:00
/* FCSR has been preset by `mips_set_personality_nan'. */
2015-01-30 15:09:36 +03:00
/*
* Record that the target has " used " math , such that the context
* just initialised , and any modifications made by the caller ,
* aren ' t discarded .
*/
set_stopped_child_used_math ( target ) ;
}
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
}
2016-05-12 12:19:08 +03:00
/*
2016-10-28 10:21:03 +03:00
* Poke at FCSR according to its mask . Set the Cause bits even
* if a corresponding Enable bit is set . This will be noticed at
* the time the thread is switched to and SIGFPE thrown accordingly .
2016-05-12 12:19:08 +03:00
*/
static void ptrace_setfcr31 ( struct task_struct * child , u32 value )
{
u32 fcr31 ;
u32 mask ;
fcr31 = child - > thread . fpu . fcr31 ;
mask = boot_cpu_data . fpu_msk31 ;
child - > thread . fpu . fcr31 = ( value & ~ mask ) | ( fcr31 & mask ) ;
}
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 .
*/
2014-07-23 17:40:13 +04:00
int ptrace_getregs ( struct task_struct * child , struct user_pt_regs __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 + + )
2014-07-23 17:40:13 +04:00
__put_user ( ( long ) regs - > regs [ i ] , ( __s64 __user * ) & data - > regs [ i ] ) ;
__put_user ( ( long ) regs - > lo , ( __s64 __user * ) & data - > lo ) ;
__put_user ( ( long ) regs - > hi , ( __s64 __user * ) & data - > hi ) ;
__put_user ( ( long ) regs - > cp0_epc , ( __s64 __user * ) & data - > cp0_epc ) ;
__put_user ( ( long ) regs - > cp0_badvaddr , ( __s64 __user * ) & data - > cp0_badvaddr ) ;
__put_user ( ( long ) regs - > cp0_status , ( __s64 __user * ) & data - > cp0_status ) ;
__put_user ( ( long ) regs - > cp0_cause , ( __s64 __user * ) & data - > cp0_cause ) ;
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 .
*/
2014-07-23 17:40:13 +04:00
int ptrace_setregs ( struct task_struct * child , struct user_pt_regs __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 + + )
2014-07-23 17:40:13 +04:00
__get_user ( regs - > regs [ i ] , ( __s64 __user * ) & data - > regs [ i ] ) ;
__get_user ( regs - > lo , ( __s64 __user * ) & data - > lo ) ;
__get_user ( regs - > hi , ( __s64 __user * ) & data - > hi ) ;
__get_user ( regs - > cp0_epc , ( __s64 __user * ) & data - > cp0_epc ) ;
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 ) ;
2014-07-23 17:40:06 +04:00
__put_user ( boot_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 ;
2015-04-04 01:27:48 +03:00
u32 value ;
2005-09-29 02:11:15 +04:00
int i ;
if ( ! access_ok ( VERIFY_READ , data , 33 * 8 ) )
return - EIO ;
2015-01-30 15:09:36 +03:00
init_fp_ctx ( child ) ;
2005-09-29 02:11:15 +04:00
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
2015-04-04 01:27:48 +03:00
__get_user ( value , data + 64 ) ;
2016-05-12 12:19:08 +03:00
ptrace_setfcr31 ( child , value ) ;
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 ;
2014-05-01 15:51:19 +04:00
if ( ! cpu_has_watch | | boot_cpu_data . watch_reg_use_cnt = = 0 )
2008-09-23 11:11:26 +04:00
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 ) ;
2014-05-01 15:51:19 +04:00
__put_user ( boot_cpu_data . watch_reg_use_cnt ,
2008-09-23 11:11:26 +04:00
& addr - > WATCH_STYLE . num_valid ) ;
2014-05-01 15:51:19 +04:00
for ( i = 0 ; i < boot_cpu_data . watch_reg_use_cnt ; i + + ) {
2008-09-23 11:11:26 +04:00
__put_user ( child - > thread . watch . mips3264 . watchlo [ i ] ,
& addr - > WATCH_STYLE . watchlo [ i ] ) ;
2016-03-02 01:19:39 +03:00
__put_user ( child - > thread . watch . mips3264 . watchhi [ i ] &
( MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW ) ,
2008-09-23 11:11:26 +04:00
& addr - > WATCH_STYLE . watchhi [ i ] ) ;
2014-05-01 15:51:19 +04:00
__put_user ( boot_cpu_data . watch_reg_masks [ i ] ,
2008-09-23 11:11:26 +04:00
& 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 ] ;
2014-05-01 15:51:19 +04:00
if ( ! cpu_has_watch | | boot_cpu_data . watch_reg_use_cnt = = 0 )
2008-09-23 11:11:26 +04:00
return - EIO ;
if ( ! access_ok ( VERIFY_READ , addr , sizeof ( struct pt_watch_regs ) ) )
return - EIO ;
/* Check the values. */
2014-05-01 15:51:19 +04:00
for ( i = 0 ; i < boot_cpu_data . watch_reg_use_cnt ; i + + ) {
2008-09-23 11:11:26 +04:00
__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 ] ) ;
2016-03-02 01:19:39 +03:00
if ( ht [ i ] & ~ MIPS_WATCHHI_MASK )
2008-09-23 11:11:26 +04:00
return - EINVAL ;
}
/* Install them. */
2014-05-01 15:51:19 +04:00
for ( i = 0 ; i < boot_cpu_data . watch_reg_use_cnt ; i + + ) {
2016-03-02 01:19:39 +03:00
if ( lt [ i ] & MIPS_WATCHLO_IRW )
2008-09-23 11:11:26 +04:00
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 */
2014-07-23 17:40:09 +04:00
# if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
static int gpr32_get ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
void * kbuf , void __user * ubuf )
2012-08-02 16:44:11 +04:00
{
struct pt_regs * regs = task_pt_regs ( target ) ;
2014-07-23 17:40:09 +04:00
u32 uregs [ ELF_NGREG ] = { } ;
2012-08-02 16:44:11 +04:00
2016-11-21 13:23:38 +03:00
mips_dump_regs32 ( uregs , regs ) ;
2014-07-23 17:40:09 +04:00
return user_regset_copyout ( & pos , & count , & kbuf , & ubuf , uregs , 0 ,
sizeof ( uregs ) ) ;
2012-08-02 16:44:11 +04:00
}
2014-07-23 17:40:09 +04:00
static int gpr32_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
2012-08-02 16:44:11 +04:00
{
2014-07-23 17:40:09 +04:00
struct pt_regs * regs = task_pt_regs ( target ) ;
u32 uregs [ ELF_NGREG ] ;
unsigned start , num_regs , i ;
int err ;
start = pos / sizeof ( u32 ) ;
num_regs = count / sizeof ( u32 ) ;
if ( start + num_regs > ELF_NGREG )
return - EIO ;
err = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , uregs , 0 ,
sizeof ( uregs ) ) ;
if ( err )
return err ;
for ( i = start ; i < num_regs ; i + + ) {
/*
* Cast all values to signed here so that if this is a 64 - bit
* kernel , the supplied 32 - bit values will be sign extended .
*/
switch ( i ) {
case MIPS32_EF_R1 . . . MIPS32_EF_R25 :
/* k0/k1 are ignored. */
case MIPS32_EF_R28 . . . MIPS32_EF_R31 :
regs - > regs [ i - MIPS32_EF_R0 ] = ( s32 ) uregs [ i ] ;
break ;
case MIPS32_EF_LO :
regs - > lo = ( s32 ) uregs [ i ] ;
break ;
case MIPS32_EF_HI :
regs - > hi = ( s32 ) uregs [ i ] ;
break ;
case MIPS32_EF_CP0_EPC :
regs - > cp0_epc = ( s32 ) uregs [ i ] ;
break ;
}
}
return 0 ;
}
# endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
# ifdef CONFIG_64BIT
static int gpr64_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 ) ;
u64 uregs [ ELF_NGREG ] = { } ;
2016-11-21 13:23:38 +03:00
mips_dump_regs64 ( uregs , regs ) ;
2014-07-23 17:40:09 +04:00
return user_regset_copyout ( & pos , & count , & kbuf , & ubuf , uregs , 0 ,
sizeof ( uregs ) ) ;
}
2012-08-02 16:44:11 +04:00
2014-07-23 17:40:09 +04:00
static int gpr64_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 * regs = task_pt_regs ( target ) ;
u64 uregs [ ELF_NGREG ] ;
unsigned start , num_regs , i ;
int err ;
start = pos / sizeof ( u64 ) ;
num_regs = count / sizeof ( u64 ) ;
if ( start + num_regs > ELF_NGREG )
return - EIO ;
2012-08-02 16:44:11 +04:00
2014-07-23 17:40:09 +04:00
err = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , uregs , 0 ,
sizeof ( uregs ) ) ;
if ( err )
return err ;
for ( i = start ; i < num_regs ; i + + ) {
switch ( i ) {
case MIPS64_EF_R1 . . . MIPS64_EF_R25 :
/* k0/k1 are ignored. */
case MIPS64_EF_R28 . . . MIPS64_EF_R31 :
regs - > regs [ i - MIPS64_EF_R0 ] = uregs [ i ] ;
break ;
case MIPS64_EF_LO :
regs - > lo = uregs [ i ] ;
break ;
case MIPS64_EF_HI :
regs - > hi = uregs [ i ] ;
break ;
case MIPS64_EF_CP0_EPC :
regs - > cp0_epc = uregs [ i ] ;
break ;
}
}
2012-08-02 16:44:11 +04:00
return 0 ;
}
2014-07-23 17:40:09 +04:00
# endif /* CONFIG_64BIT */
2012-08-02 16:44:11 +04:00
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
2015-01-30 15:09:36 +03:00
init_fp_ctx ( target ) ;
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 ) ) ;
2017-03-27 17:10:58 +03:00
BUILD_BUG_ON ( sizeof ( fpr_val ) ! = sizeof ( elf_fpreg_t ) ) ;
for ( i = 0 ; i < NUM_FPU_REGS & & count > = sizeof ( elf_fpreg_t ) ; i + + ) {
2014-01-27 19:23:07 +04:00
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 ,
} ;
2015-07-29 23:44:53 +03:00
struct pt_regs_offset {
const char * name ;
int offset ;
} ;
# define REG_OFFSET_NAME(reg, r) { \
. name = # reg , \
. offset = offsetof ( struct pt_regs , r ) \
}
# define REG_OFFSET_END { \
. name = NULL , \
. offset = 0 \
}
static const struct pt_regs_offset regoffset_table [ ] = {
REG_OFFSET_NAME ( r0 , regs [ 0 ] ) ,
REG_OFFSET_NAME ( r1 , regs [ 1 ] ) ,
REG_OFFSET_NAME ( r2 , regs [ 2 ] ) ,
REG_OFFSET_NAME ( r3 , regs [ 3 ] ) ,
REG_OFFSET_NAME ( r4 , regs [ 4 ] ) ,
REG_OFFSET_NAME ( r5 , regs [ 5 ] ) ,
REG_OFFSET_NAME ( r6 , regs [ 6 ] ) ,
REG_OFFSET_NAME ( r7 , regs [ 7 ] ) ,
REG_OFFSET_NAME ( r8 , regs [ 8 ] ) ,
REG_OFFSET_NAME ( r9 , regs [ 9 ] ) ,
REG_OFFSET_NAME ( r10 , regs [ 10 ] ) ,
REG_OFFSET_NAME ( r11 , regs [ 11 ] ) ,
REG_OFFSET_NAME ( r12 , regs [ 12 ] ) ,
REG_OFFSET_NAME ( r13 , regs [ 13 ] ) ,
REG_OFFSET_NAME ( r14 , regs [ 14 ] ) ,
REG_OFFSET_NAME ( r15 , regs [ 15 ] ) ,
REG_OFFSET_NAME ( r16 , regs [ 16 ] ) ,
REG_OFFSET_NAME ( r17 , regs [ 17 ] ) ,
REG_OFFSET_NAME ( r18 , regs [ 18 ] ) ,
REG_OFFSET_NAME ( r19 , regs [ 19 ] ) ,
REG_OFFSET_NAME ( r20 , regs [ 20 ] ) ,
REG_OFFSET_NAME ( r21 , regs [ 21 ] ) ,
REG_OFFSET_NAME ( r22 , regs [ 22 ] ) ,
REG_OFFSET_NAME ( r23 , regs [ 23 ] ) ,
REG_OFFSET_NAME ( r24 , regs [ 24 ] ) ,
REG_OFFSET_NAME ( r25 , regs [ 25 ] ) ,
REG_OFFSET_NAME ( r26 , regs [ 26 ] ) ,
REG_OFFSET_NAME ( r27 , regs [ 27 ] ) ,
REG_OFFSET_NAME ( r28 , regs [ 28 ] ) ,
REG_OFFSET_NAME ( r29 , regs [ 29 ] ) ,
REG_OFFSET_NAME ( r30 , regs [ 30 ] ) ,
REG_OFFSET_NAME ( r31 , regs [ 31 ] ) ,
REG_OFFSET_NAME ( c0_status , cp0_status ) ,
REG_OFFSET_NAME ( hi , hi ) ,
REG_OFFSET_NAME ( lo , lo ) ,
# ifdef CONFIG_CPU_HAS_SMARTMIPS
REG_OFFSET_NAME ( acx , acx ) ,
# endif
REG_OFFSET_NAME ( c0_badvaddr , cp0_badvaddr ) ,
REG_OFFSET_NAME ( c0_cause , cp0_cause ) ,
REG_OFFSET_NAME ( c0_epc , cp0_epc ) ,
# ifdef CONFIG_CPU_CAVIUM_OCTEON
REG_OFFSET_NAME ( mpl0 , mpl [ 0 ] ) ,
REG_OFFSET_NAME ( mpl1 , mpl [ 1 ] ) ,
REG_OFFSET_NAME ( mpl2 , mpl [ 2 ] ) ,
REG_OFFSET_NAME ( mtp0 , mtp [ 0 ] ) ,
REG_OFFSET_NAME ( mtp1 , mtp [ 1 ] ) ,
REG_OFFSET_NAME ( mtp2 , mtp [ 2 ] ) ,
# endif
REG_OFFSET_END ,
} ;
/**
* regs_query_register_offset ( ) - query register offset from its name
* @ name : the name of a register
*
* regs_query_register_offset ( ) returns the offset of a register in struct
* pt_regs from its name . If the name is invalid , this returns - EINVAL ;
*/
int regs_query_register_offset ( const char * name )
{
const struct pt_regs_offset * roff ;
for ( roff = regoffset_table ; roff - > name ! = NULL ; roff + + )
if ( ! strcmp ( roff - > name , name ) )
return roff - > offset ;
return - EINVAL ;
}
2014-07-23 17:40:09 +04:00
# if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
2012-08-02 16:44:11 +04:00
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 ) ,
2014-07-23 17:40:09 +04:00
. get = gpr32_get ,
. set = gpr32_set ,
2012-08-02 16:44:11 +04:00
} ,
[ 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 ) ,
} ;
2014-07-23 17:40:09 +04:00
# endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
# ifdef CONFIG_64BIT
2012-08-02 16:44:11 +04:00
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 ) ,
2014-07-23 17:40:09 +04:00
. get = gpr64_get ,
. set = gpr64_set ,
2012-08-02 16:44:11 +04:00
} ,
[ 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 = {
2014-07-23 17:40:09 +04:00
. name = " mips64 " ,
2012-08-02 16:44:11 +04:00
. e_machine = ELF_ARCH ,
. ei_osabi = ELF_OSABI ,
. regsets = mips64_regsets ,
2014-07-23 17:40:09 +04:00
. n = ARRAY_SIZE ( mips64_regsets ) ,
2012-08-02 16:44:11 +04:00
} ;
2014-07-23 17:40:09 +04:00
# endif /* CONFIG_64BIT */
2012-08-02 16:44:11 +04:00
const struct user_regset_view * task_user_regset_view ( struct task_struct * task )
{
# ifdef CONFIG_32BIT
return & user_mips_view ;
2014-07-23 17:40:09 +04:00
# else
2012-08-02 16:44:11 +04:00
# ifdef CONFIG_MIPS32_O32
2014-07-23 17:40:09 +04:00
if ( test_tsk_thread_flag ( task , TIF_32BIT_REGS ) )
return & user_mips_view ;
2012-08-02 16:44:11 +04:00
# endif
return & user_mips64_view ;
2014-07-23 17:40:09 +04:00
# endif
2012-08-02 16:44:11 +04:00
}
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 */
2014-07-23 17:40:06 +04:00
tmp = boot_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
2015-01-30 15:09:36 +03:00
init_fp_ctx ( child ) ;
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 :
2016-10-28 10:20:09 +03:00
init_fp_ctx ( child ) ;
2016-05-12 12:19:08 +03:00
ptrace_setfcr31 ( child , 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
{
2013-05-29 03:07:19 +04:00
user_exit ( ) ;
2015-02-03 19:08:17 +03:00
current_thread_info ( ) - > syscall = syscall ;
2012-09-26 23:30:47 +04:00
if ( test_thread_flag ( TIF_SYSCALL_TRACE ) & &
tracehook_report_syscall_entry ( regs ) )
2016-06-02 22:33:44 +03:00
return - 1 ;
2017-06-14 01:28:47 +03:00
# ifdef CONFIG_SECCOMP
if ( unlikely ( test_thread_flag ( TIF_SECCOMP ) ) ) {
int ret , i ;
struct seccomp_data sd ;
2017-08-11 23:56:50 +03:00
unsigned long args [ 6 ] ;
2017-06-14 01:28:47 +03:00
sd . nr = syscall ;
sd . arch = syscall_get_arch ( ) ;
2017-08-11 23:56:50 +03:00
syscall_get_arguments ( current , regs , 0 , 6 , args ) ;
for ( i = 0 ; i < 6 ; i + + )
sd . args [ i ] = args [ i ] ;
2017-06-14 01:28:47 +03:00
sd . instruction_pointer = KSTK_EIP ( current ) ;
ret = __secure_computing ( & sd ) ;
if ( ret = = - 1 )
return ret ;
}
# endif
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-03-11 21:29:28 +04:00
audit_syscall_entry ( syscall , regs - > regs [ 4 ] , regs - > regs [ 5 ] ,
2012-01-03 23:23:06 +04:00
regs - > regs [ 6 ] , regs - > regs [ 7 ] ) ;
2017-06-29 12:12:36 +03:00
/*
* Negative syscall numbers are mistaken for rejected syscalls , but
* won ' t have had the return value set appropriately , so we do so now .
*/
if ( syscall < 0 )
syscall_set_return_value ( current , regs , - ENOSYS , 0 ) ;
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 ) ) )
2017-06-29 12:12:34 +03:00
trace_sys_exit ( regs , regs_return_value ( regs ) ) ;
2013-09-06 22:24:48 +04:00
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
}