2 * Copyright 2003 PathScale, Inc.
3 * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
5 * Licensed under the GPL
9 #include <linux/sched.h>
10 #include <linux/errno.h>
11 #define __FRAME_OFFSETS
12 #include <asm/ptrace.h>
13 #include <linux/uaccess.h>
14 #include <asm/ptrace-abi.h>
17 * determines which flags the user has access to.
18 * 1 = access 0 = no access
20 #define FLAG_MASK 0x44dd5UL
22 static const int reg_offsets
[] =
26 [R10
>> 3] = HOST_R10
,
27 [R11
>> 3] = HOST_R11
,
28 [R12
>> 3] = HOST_R12
,
29 [R13
>> 3] = HOST_R13
,
30 [R14
>> 3] = HOST_R14
,
31 [R15
>> 3] = HOST_R15
,
43 [FS_BASE
>> 3] = HOST_FS_BASE
,
44 [GS_BASE
>> 3] = HOST_GS_BASE
,
49 [EFLAGS
>> 3] = HOST_EFLAGS
,
50 [ORIG_RAX
>> 3] = HOST_ORIG_AX
,
53 int putreg(struct task_struct
*child
, int regno
, unsigned long value
)
57 * Some code in the 64bit emulation may not be 64bit clean.
58 * Don't take any chances.
60 if (test_tsk_thread_flag(child
, TIF_IA32
))
84 /* Update the syscall number. */
85 UPT_SYSCALL_NR(&child
->thread
.regs
.regs
) = value
;
94 if (value
&& (value
& 3) != 3)
101 if (!((value
>> 48) == 0 || (value
>> 48) == 0xffff))
107 child
->thread
.regs
.regs
.gp
[HOST_EFLAGS
] |= value
;
111 panic("Bad register in putreg(): %d\n", regno
);
114 child
->thread
.regs
.regs
.gp
[reg_offsets
[regno
>> 3]] = value
;
118 int poke_user(struct task_struct
*child
, long addr
, long data
)
120 if ((addr
& 3) || addr
< 0)
123 if (addr
< MAX_REG_OFFSET
)
124 return putreg(child
, addr
, data
);
125 else if ((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
126 (addr
<= offsetof(struct user
, u_debugreg
[7]))) {
127 addr
-= offsetof(struct user
, u_debugreg
[0]);
129 if ((addr
== 4) || (addr
== 5))
131 child
->thread
.arch
.debugregs
[addr
] = data
;
137 unsigned long getreg(struct task_struct
*child
, int regno
)
139 unsigned long mask
= ~0UL;
141 if (test_tsk_thread_flag(child
, TIF_IA32
))
176 panic("Bad register in getreg: %d\n", regno
);
178 return mask
& child
->thread
.regs
.regs
.gp
[reg_offsets
[regno
>> 3]];
181 int peek_user(struct task_struct
*child
, long addr
, long data
)
183 /* read the word at location addr in the USER area. */
186 if ((addr
& 3) || addr
< 0)
189 tmp
= 0; /* Default return condition */
190 if (addr
< MAX_REG_OFFSET
)
191 tmp
= getreg(child
, addr
);
192 else if ((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
193 (addr
<= offsetof(struct user
, u_debugreg
[7]))) {
194 addr
-= offsetof(struct user
, u_debugreg
[0]);
196 tmp
= child
->thread
.arch
.debugregs
[addr
];
198 return put_user(tmp
, (unsigned long *) data
);
201 /* XXX Mostly copied from sys-i386 */
202 int is_syscall(unsigned long addr
)
204 unsigned short instr
;
207 n
= copy_from_user(&instr
, (void __user
*) addr
, sizeof(instr
));
210 * access_process_vm() grants access to vsyscall and stub,
211 * while copy_from_user doesn't. Maybe access_process_vm is
212 * slow, but that doesn't matter, since it will be called only
213 * in case of singlestepping, if copy_from_user failed.
215 n
= access_process_vm(current
, addr
, &instr
, sizeof(instr
),
217 if (n
!= sizeof(instr
)) {
218 printk("is_syscall : failed to read instruction from "
224 return instr
== 0x050f;
227 static int get_fpregs(struct user_i387_struct __user
*buf
, struct task_struct
*child
)
229 int err
, n
, cpu
= ((struct thread_info
*) child
->stack
)->cpu
;
230 struct user_i387_struct fpregs
;
232 err
= save_i387_registers(userspace_pid
[cpu
],
233 (unsigned long *) &fpregs
);
237 n
= copy_to_user(buf
, &fpregs
, sizeof(fpregs
));
244 static int set_fpregs(struct user_i387_struct __user
*buf
, struct task_struct
*child
)
246 int n
, cpu
= ((struct thread_info
*) child
->stack
)->cpu
;
247 struct user_i387_struct fpregs
;
249 n
= copy_from_user(&fpregs
, buf
, sizeof(fpregs
));
253 return restore_i387_registers(userspace_pid
[cpu
],
254 (unsigned long *) &fpregs
);
257 long subarch_ptrace(struct task_struct
*child
, long request
,
258 unsigned long addr
, unsigned long data
)
261 void __user
*datap
= (void __user
*) data
;
264 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
265 ret
= get_fpregs(datap
, child
);
267 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
268 ret
= set_fpregs(datap
, child
);
270 case PTRACE_ARCH_PRCTL
:
271 /* XXX Calls ptrace on the host - needs some SMP thinking */
272 ret
= arch_prctl(child
, data
, (void __user
*) addr
);