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
*/
2012-10-08 06:27:32 +04:00
# include <linux/mm.h>
# include <linux/sched.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2015-06-25 23:44:11 +03:00
# include <asm/ptrace-abi.h>
2012-10-08 06:27:32 +04:00
# include <skas.h>
2005-04-17 02:20:36 +04:00
2008-02-05 09:30:49 +03:00
extern int arch_switch_tls ( struct task_struct * to ) ;
2007-10-16 12:26:58 +04:00
2008-02-05 09:30:49 +03:00
void arch_switch_to ( struct task_struct * to )
2005-04-17 02:20:36 +04:00
{
2008-02-05 09:30:49 +03:00
int err = arch_switch_tls ( to ) ;
2006-03-31 14:30:24 +04:00
if ( ! err )
return ;
if ( err ! = - EINVAL )
2007-10-16 12:27:00 +04:00
printk ( KERN_WARNING " arch_switch_tls failed, errno %d, "
" not EINVAL \n " , - err ) ;
2006-03-31 14:30:24 +04:00
else
2007-10-16 12:26:58 +04:00
printk ( KERN_WARNING " arch_switch_tls failed, errno = EINVAL \n " ) ;
2005-04-17 02:20:36 +04:00
}
int is_syscall ( unsigned long addr )
{
unsigned short instr ;
int n ;
n = copy_from_user ( & instr , ( void __user * ) addr , sizeof ( instr ) ) ;
2007-10-16 12:27:00 +04:00
if ( n ) {
2006-03-27 13:14:34 +04:00
/* access_process_vm() grants access to vsyscall and stub,
* while copy_from_user doesn ' t . Maybe access_process_vm is
* slow , but that doesn ' t matter , since it will be called only
* in case of singlestepping , if copy_from_user failed .
*/
2016-10-13 03:20:20 +03:00
n = access_process_vm ( current , addr , & instr , sizeof ( instr ) ,
FOLL_FORCE ) ;
2007-10-16 12:27:00 +04:00
if ( n ! = sizeof ( instr ) ) {
printk ( KERN_ERR " is_syscall : failed to read "
" instruction from 0x%lx \n " , addr ) ;
return 1 ;
2006-03-27 13:14:34 +04:00
}
2005-04-17 02:20:36 +04:00
}
/* int 0x80 or sysenter */
2007-10-16 12:27:00 +04:00
return ( instr = = 0x80cd ) | | ( instr = = 0x340f ) ;
2005-04-17 02:20:36 +04:00
}
/* determines which flags the user has access to. */
/* 1 = access 0 = no access */
# define FLAG_MASK 0x00044dd5
2011-08-18 23:02:29 +04:00
static const int reg_offsets [ ] = {
2011-08-18 23:10:09 +04:00
[ EBX ] = HOST_BX ,
[ ECX ] = HOST_CX ,
[ EDX ] = HOST_DX ,
[ ESI ] = HOST_SI ,
[ EDI ] = HOST_DI ,
[ EBP ] = HOST_BP ,
[ EAX ] = HOST_AX ,
2011-08-18 23:02:29 +04:00
[ DS ] = HOST_DS ,
[ ES ] = HOST_ES ,
[ FS ] = HOST_FS ,
[ GS ] = HOST_GS ,
[ EIP ] = HOST_IP ,
[ CS ] = HOST_CS ,
[ EFL ] = HOST_EFLAGS ,
[ UESP ] = HOST_SP ,
[ SS ] = HOST_SS ,
2015-12-29 23:35:44 +03:00
[ ORIG_EAX ] = HOST_ORIG_AX ,
2011-08-18 23:02:29 +04:00
} ;
2005-04-17 02:20:36 +04:00
int putreg ( struct task_struct * child , int regno , unsigned long value )
{
regno > > = 2 ;
switch ( regno ) {
2011-08-18 23:02:29 +04:00
case EBX :
case ECX :
case EDX :
case ESI :
case EDI :
case EBP :
case EAX :
case EIP :
case UESP :
2016-08-02 00:01:56 +03:00
break ;
2015-12-29 23:35:44 +03:00
case ORIG_EAX :
2016-08-02 00:01:56 +03:00
/* Update the syscall number. */
UPT_SYSCALL_NR ( & child - > thread . regs . regs ) = value ;
2011-08-18 23:02:29 +04:00
break ;
2005-04-17 02:20:36 +04:00
case FS :
if ( value & & ( value & 3 ) ! = 3 )
return - EIO ;
2011-08-18 23:02:29 +04:00
break ;
2005-04-17 02:20:36 +04:00
case GS :
if ( value & & ( value & 3 ) ! = 3 )
return - EIO ;
2011-08-18 23:02:29 +04:00
break ;
2005-04-17 02:20:36 +04:00
case DS :
case ES :
if ( value & & ( value & 3 ) ! = 3 )
return - EIO ;
value & = 0xffff ;
break ;
case SS :
case CS :
if ( ( value & 3 ) ! = 3 )
return - EIO ;
value & = 0xffff ;
break ;
case EFL :
value & = FLAG_MASK ;
2011-08-18 23:02:29 +04:00
child - > thread . regs . regs . gp [ HOST_EFLAGS ] | = value ;
return 0 ;
default :
panic ( " Bad register in putreg() : %d \n " , regno ) ;
2005-04-17 02:20:36 +04:00
}
2011-08-18 23:02:29 +04:00
child - > thread . regs . regs . gp [ reg_offsets [ regno ] ] = value ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
int poke_user ( struct task_struct * child , long addr , long data )
{
2007-10-16 12:27:00 +04:00
if ( ( addr & 3 ) | | addr < 0 )
return - EIO ;
if ( addr < MAX_REG_OFFSET )
return putreg ( child , addr , data ) ;
else if ( ( addr > = offsetof ( struct user , u_debugreg [ 0 ] ) ) & &
( addr < = offsetof ( struct user , u_debugreg [ 7 ] ) ) ) {
addr - = offsetof ( struct user , u_debugreg [ 0 ] ) ;
addr = addr > > 2 ;
if ( ( addr = = 4 ) | | ( addr = = 5 ) )
return - EIO ;
child - > thread . arch . debugregs [ addr ] = data ;
return 0 ;
}
return - EIO ;
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
}
2005-04-17 02:20:36 +04:00
unsigned long getreg ( struct task_struct * child , int regno )
{
2011-08-18 23:02:29 +04:00
unsigned long mask = ~ 0UL ;
2005-04-17 02:20:36 +04:00
regno > > = 2 ;
switch ( regno ) {
case FS :
case GS :
case DS :
case ES :
case SS :
case CS :
2011-08-18 23:02:29 +04:00
mask = 0xffff ;
break ;
case EIP :
case UESP :
case EAX :
case EBX :
case ECX :
case EDX :
case ESI :
case EDI :
case EBP :
case EFL :
2015-12-29 23:35:44 +03:00
case ORIG_EAX :
2011-08-18 23:02:29 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
2011-08-18 23:02:29 +04:00
panic ( " Bad register in getreg() : %d \n " , regno ) ;
2005-04-17 02:20:36 +04:00
}
2011-08-18 23:02:29 +04:00
return mask & child - > thread . regs . regs . gp [ reg_offsets [ regno ] ] ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:27:00 +04:00
/* read the word at location addr in the USER area. */
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
int peek_user ( struct task_struct * child , long addr , long data )
{
2006-03-31 14:30:15 +04:00
unsigned long tmp ;
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
2006-03-31 14:30:15 +04:00
if ( ( addr & 3 ) | | addr < 0 )
return - EIO ;
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
2006-03-31 14:30:15 +04:00
tmp = 0 ; /* Default return condition */
2007-10-16 12:27:00 +04:00
if ( addr < MAX_REG_OFFSET ) {
2006-03-31 14:30:15 +04:00
tmp = getreg ( child , addr ) ;
}
2007-10-16 12:27:00 +04:00
else if ( ( addr > = offsetof ( struct user , u_debugreg [ 0 ] ) ) & &
( addr < = offsetof ( struct user , u_debugreg [ 7 ] ) ) ) {
2006-03-31 14:30:15 +04:00
addr - = offsetof ( struct user , u_debugreg [ 0 ] ) ;
addr = addr > > 2 ;
tmp = child - > thread . arch . debugregs [ addr ] ;
}
return put_user ( tmp , ( unsigned long __user * ) data ) ;
[PATCH] uml: S390 preparation, peekusr/pokeusr defined by subarch
s390 needs to change some parts of arch/um/kernel/ptrace.c. Thus, the code
regarding PEEKUSER and POKEUSER are shifted to arch/um/sys-<subarch>/ptrace.c.
Also s390 debug registers need to be updated, when singlestepping is switched
on / off. Thus, setting/resetting of singlestepping is centralized in the new
function set_singlestep(), which also inserts the macro
SUBARCH_SET_SINGLESTEP(mode), if defined.
Finally, s390 has the "ieee_instruction_pointer" in its
registers, which also is allowed to be read via
ptrace( PTRACE_PEEKUSER, getpid(), PT_IEEE_IP, 0);
To implement this feature, sys_ptrace inserts the macro
SUBARCH_PTRACE_SPECIAL, if defined.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-07 08:30:46 +04:00
}
2011-09-15 03:21:37 +04:00
static int get_fpregs ( struct user_i387_struct __user * buf , struct task_struct * child )
2005-04-17 02:20:36 +04:00
{
2016-09-14 00:29:23 +03:00
int err , n , cpu = task_cpu ( child ) ;
2008-05-13 01:01:50 +04:00
struct user_i387_struct fpregs ;
2005-04-17 02:20:36 +04:00
2016-03-19 19:58:41 +03:00
err = save_i387_registers ( userspace_pid [ cpu ] ,
( unsigned long * ) & fpregs ) ;
2007-10-16 12:27:16 +04:00
if ( err )
return err ;
2008-05-13 01:01:50 +04:00
n = copy_to_user ( buf , & fpregs , sizeof ( fpregs ) ) ;
2007-10-16 12:27:16 +04:00
if ( n > 0 )
return - EFAULT ;
return n ;
2005-04-17 02:20:36 +04:00
}
2011-09-15 03:21:37 +04:00
static int set_fpregs ( struct user_i387_struct __user * buf , struct task_struct * child )
2005-04-17 02:20:36 +04:00
{
2016-09-14 00:29:23 +03:00
int n , cpu = task_cpu ( child ) ;
2008-05-13 01:01:50 +04:00
struct user_i387_struct fpregs ;
2005-04-17 02:20:36 +04:00
2008-05-13 01:01:50 +04:00
n = copy_from_user ( & fpregs , buf , sizeof ( fpregs ) ) ;
2007-10-16 12:27:16 +04:00
if ( n > 0 )
2007-10-16 12:27:00 +04:00
return - EFAULT ;
2007-10-16 12:27:16 +04:00
2016-03-19 19:58:41 +03:00
return restore_i387_registers ( userspace_pid [ cpu ] ,
2008-05-13 01:01:50 +04:00
( unsigned long * ) & fpregs ) ;
2005-04-17 02:20:36 +04:00
}
2011-09-15 03:21:37 +04:00
static int get_fpxregs ( struct user_fxsr_struct __user * buf , struct task_struct * child )
2005-04-17 02:20:36 +04:00
{
2016-09-14 00:29:23 +03:00
int err , n , cpu = task_cpu ( child ) ;
2008-05-13 01:01:50 +04:00
struct user_fxsr_struct fpregs ;
2005-04-17 02:20:36 +04:00
2008-05-13 01:01:50 +04:00
err = save_fpx_registers ( userspace_pid [ cpu ] , ( unsigned long * ) & fpregs ) ;
2007-10-16 12:27:00 +04:00
if ( err )
2007-10-16 12:27:16 +04:00
return err ;
2008-05-13 01:01:50 +04:00
n = copy_to_user ( buf , & fpregs , sizeof ( fpregs ) ) ;
2007-10-16 12:27:16 +04:00
if ( n > 0 )
2007-10-16 12:27:00 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:16 +04:00
return n ;
2005-04-17 02:20:36 +04:00
}
2011-09-15 03:21:37 +04:00
static int set_fpxregs ( struct user_fxsr_struct __user * buf , struct task_struct * child )
2005-04-17 02:20:36 +04:00
{
2016-09-14 00:29:23 +03:00
int n , cpu = task_cpu ( child ) ;
2008-05-13 01:01:50 +04:00
struct user_fxsr_struct fpregs ;
2007-10-16 12:27:16 +04:00
2008-05-13 01:01:50 +04:00
n = copy_from_user ( & fpregs , buf , sizeof ( fpregs ) ) ;
2007-10-16 12:27:16 +04:00
if ( n > 0 )
return - EFAULT ;
2008-05-13 01:01:50 +04:00
return restore_fpx_registers ( userspace_pid [ cpu ] ,
( unsigned long * ) & fpregs ) ;
2005-04-17 02:20:36 +04:00
}
2010-10-28 02:33:47 +04:00
long subarch_ptrace ( struct task_struct * child , long request ,
unsigned long addr , unsigned long data )
2007-10-16 12:27:16 +04:00
{
2011-09-15 03:21:34 +04:00
int ret = - EIO ;
void __user * datap = ( void __user * ) data ;
switch ( request ) {
2011-09-15 03:21:37 +04:00
case PTRACE_GETFPREGS : /* Get the child FPU state. */
ret = get_fpregs ( datap , child ) ;
break ;
case PTRACE_SETFPREGS : /* Set the child FPU state. */
ret = set_fpregs ( datap , child ) ;
break ;
2011-09-15 03:21:34 +04:00
case PTRACE_GETFPXREGS : /* Get the child FPU state. */
ret = get_fpxregs ( datap , child ) ;
break ;
case PTRACE_SETFPXREGS : /* Set the child FPU state. */
ret = set_fpxregs ( datap , child ) ;
break ;
2011-09-15 03:21:37 +04:00
default :
ret = - EIO ;
2011-09-15 03:21:34 +04:00
}
return ret ;
2007-10-16 12:27:16 +04:00
}