2005-04-17 02:20:36 +04:00
/*
* Copyright 2003 PathScale , Inc .
2007-10-16 12:27:18 +04:00
* Copyright ( C ) 2003 - 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:20 +03:00
# include <linux/mm.h>
2005-05-21 00:59:07 +04:00
# include <linux/sched.h>
# include <linux/errno.h>
2008-02-05 09:31:20 +03:00
# define __FRAME_OFFSETS
# include <asm/ptrace.h>
2005-05-21 00:59:07 +04:00
# include <asm/uaccess.h>
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:18 +04:00
/*
* determines which flags the user has access to .
* 1 = access 0 = no access
*/
2005-04-17 02:20:36 +04:00
# define FLAG_MASK 0x44dd5UL
2011-08-18 23:02:29 +04:00
static const int reg_offsets [ ] =
2005-04-17 02:20:36 +04:00
{
2011-08-18 23:02:29 +04:00
[ R8 > > 3 ] = HOST_R8 ,
[ R9 > > 3 ] = HOST_R9 ,
[ R10 > > 3 ] = HOST_R10 ,
[ R11 > > 3 ] = HOST_R11 ,
[ R12 > > 3 ] = HOST_R12 ,
[ R13 > > 3 ] = HOST_R13 ,
[ R14 > > 3 ] = HOST_R14 ,
[ R15 > > 3 ] = HOST_R15 ,
[ RIP > > 3 ] = HOST_IP ,
[ RSP > > 3 ] = HOST_SP ,
2011-08-18 23:10:09 +04:00
[ RAX > > 3 ] = HOST_AX ,
[ RBX > > 3 ] = HOST_BX ,
[ RCX > > 3 ] = HOST_CX ,
[ RDX > > 3 ] = HOST_DX ,
[ RSI > > 3 ] = HOST_SI ,
[ RDI > > 3 ] = HOST_DI ,
[ RBP > > 3 ] = HOST_BP ,
2011-08-18 23:02:29 +04:00
[ CS > > 3 ] = HOST_CS ,
[ SS > > 3 ] = HOST_SS ,
[ FS_BASE > > 3 ] = HOST_FS_BASE ,
[ GS_BASE > > 3 ] = HOST_GS_BASE ,
[ DS > > 3 ] = HOST_DS ,
[ ES > > 3 ] = HOST_ES ,
[ FS > > 3 ] = HOST_FS ,
[ GS > > 3 ] = HOST_GS ,
[ EFLAGS > > 3 ] = HOST_EFLAGS ,
2011-08-18 23:12:19 +04:00
[ ORIG_RAX > > 3 ] = HOST_ORIG_AX ,
2011-08-18 23:02:29 +04:00
} ;
2005-04-17 02:20:36 +04:00
2011-08-18 23:02:29 +04:00
int putreg ( struct task_struct * child , int regno , unsigned long value )
{
2005-04-17 02:20:36 +04:00
# ifdef TIF_IA32
2008-02-05 09:31:20 +03:00
/*
* Some code in the 64 bit emulation may not be 64 bit clean .
* Don ' t take any chances .
*/
2005-04-17 02:20:36 +04:00
if ( test_tsk_thread_flag ( child , TIF_IA32 ) )
value & = 0xffffffff ;
# endif
2008-02-05 09:31:20 +03:00
switch ( regno ) {
2011-08-18 23:02:29 +04:00
case R8 :
case R9 :
case R10 :
case R11 :
case R12 :
case R13 :
case R14 :
case R15 :
case RIP :
case RSP :
case RAX :
case RBX :
case RCX :
case RDX :
case RSI :
case RDI :
case RBP :
case ORIG_RAX :
break ;
2005-04-17 02:20:36 +04:00
case FS :
case GS :
case DS :
case ES :
case SS :
case CS :
if ( value & & ( value & 3 ) ! = 3 )
return - EIO ;
value & = 0xffff ;
break ;
case FS_BASE :
case GS_BASE :
if ( ! ( ( value > > 48 ) = = 0 | | ( value > > 48 ) = = 0xffff ) )
return - EIO ;
break ;
case EFLAGS :
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 > > 3 ] ] = 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:18 +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 ] ) ) & &
2008-02-05 09:31:20 +03:00
( addr < = offsetof ( struct user , u_debugreg [ 7 ] ) ) ) {
2007-10-16 12:27:18 +04:00
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 ;
# ifdef TIF_IA32
if ( test_tsk_thread_flag ( child , TIF_IA32 ) )
mask = 0xffffffff ;
# endif
2005-04-17 02:20:36 +04:00
switch ( regno ) {
2011-08-18 23:02:29 +04:00
case R8 :
case R9 :
case R10 :
case R11 :
case R12 :
case R13 :
case R14 :
case R15 :
case RIP :
case RSP :
case RAX :
case RBX :
case RCX :
case RDX :
case RSI :
case RDI :
case RBP :
case ORIG_RAX :
case EFLAGS :
case FS_BASE :
case GS_BASE :
break ;
2005-04-17 02:20:36 +04:00
case FS :
case GS :
case DS :
case ES :
case SS :
case CS :
2011-08-18 23:02:29 +04:00
mask = 0xffff ;
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 > > 3 ] ] ;
2005-04-17 02:20:36 +04:00
}
[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 )
{
/* read the word at location addr in the USER area. */
2007-10-16 12:27:18 +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
2007-10-16 12:27:18 +04:00
if ( ( addr & 3 ) | | addr < 0 )
return - EIO ;
tmp = 0 ; /* Default return condition */
2008-02-05 09:31:20 +03:00
if ( addr < MAX_REG_OFFSET )
2007-10-16 12:27:18 +04:00
tmp = getreg ( child , addr ) ;
else if ( ( addr > = offsetof ( struct user , u_debugreg [ 0 ] ) ) & &
2008-02-05 09:31:20 +03:00
( addr < = offsetof ( struct user , u_debugreg [ 7 ] ) ) ) {
2007-10-16 12:27:18 +04:00
addr - = offsetof ( struct user , u_debugreg [ 0 ] ) ;
addr = addr > > 2 ;
tmp = child - > thread . arch . debugregs [ addr ] ;
}
return put_user ( tmp , ( unsigned long * ) data ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:14:34 +04:00
/* XXX Mostly copied from sys-i386 */
2005-04-17 02:20:36 +04:00
int is_syscall ( unsigned long addr )
{
2006-03-27 13:14:34 +04:00
unsigned short instr ;
int n ;
n = copy_from_user ( & instr , ( void __user * ) addr , sizeof ( instr ) ) ;
2008-02-05 09:31:20 +03:00
if ( n ) {
/*
* access_process_vm ( ) grants access to vsyscall and stub ,
2006-03-27 13:14:34 +04:00
* 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 .
*/
n = access_process_vm ( current , addr , & instr , sizeof ( instr ) , 0 ) ;
2007-10-16 12:27:18 +04:00
if ( n ! = sizeof ( instr ) ) {
2006-03-27 13:14:34 +04:00
printk ( " is_syscall : failed to read instruction from "
" 0x%lx \n " , addr ) ;
2007-10-16 12:27:18 +04:00
return 1 ;
2006-03-27 13:14:34 +04:00
}
}
/* sysenter */
2007-10-16 12:27:18 +04:00
return instr = = 0x050f ;
2005-04-17 02:20:36 +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
{
2007-10-16 12:27:16 +04:00
int err , n , cpu = ( ( struct thread_info * ) child - > stack ) - > cpu ;
long fpregs [ HOST_FP_SIZE ] ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:16 +04:00
BUG_ON ( sizeof ( * buf ) ! = sizeof ( fpregs ) ) ;
err = save_fp_registers ( userspace_pid [ cpu ] , fpregs ) ;
if ( err )
return err ;
2007-10-29 07:36:10 +03:00
n = copy_to_user ( buf , fpregs , sizeof ( fpregs ) ) ;
2008-02-05 09:31:20 +03:00
if ( n > 0 )
2007-10-16 12:27:16 +04:00
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
{
2007-10-16 12:27:16 +04:00
int n , cpu = ( ( struct thread_info * ) child - > stack ) - > cpu ;
long fpregs [ HOST_FP_SIZE ] ;
BUG_ON ( sizeof ( * buf ) ! = sizeof ( fpregs ) ) ;
2007-10-29 07:36:10 +03:00
n = copy_from_user ( fpregs , buf , sizeof ( fpregs ) ) ;
2007-10-16 12:27:16 +04:00
if ( n > 0 )
return - EFAULT ;
return restore_fp_registers ( userspace_pid [ cpu ] , 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 )
2005-04-17 02:20:36 +04:00
{
2011-09-15 03:21:37 +04:00
int ret = - EIO ;
void __user * datap = ( void __user * ) data ;
switch ( request ) {
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 ;
case PTRACE_ARCH_PRCTL :
/* XXX Calls ptrace on the host - needs some SMP thinking */
ret = arch_prctl ( child , data , ( void __user * ) addr ) ;
break ;
}
return ret ;
2005-04-17 02:20:36 +04:00
}