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 #include <linux/regset.h>
12 #define __FRAME_OFFSETS
13 #include <asm/ptrace.h>
14 #include <linux/uaccess.h>
15 #include <registers.h>
16 #include <asm/ptrace-abi.h>
19 * determines which flags the user has access to.
20 * 1 = access 0 = no access
22 #define FLAG_MASK 0x44dd5UL
24 static const int reg_offsets
[] =
28 [R10
>> 3] = HOST_R10
,
29 [R11
>> 3] = HOST_R11
,
30 [R12
>> 3] = HOST_R12
,
31 [R13
>> 3] = HOST_R13
,
32 [R14
>> 3] = HOST_R14
,
33 [R15
>> 3] = HOST_R15
,
45 [FS_BASE
>> 3] = HOST_FS_BASE
,
46 [GS_BASE
>> 3] = HOST_GS_BASE
,
51 [EFLAGS
>> 3] = HOST_EFLAGS
,
52 [ORIG_RAX
>> 3] = HOST_ORIG_AX
,
55 int putreg(struct task_struct
*child
, int regno
, unsigned long value
)
78 /* Update the syscall number. */
79 UPT_SYSCALL_NR(&child
->thread
.regs
.regs
) = value
;
88 if (value
&& (value
& 3) != 3)
95 if (!((value
>> 48) == 0 || (value
>> 48) == 0xffff))
101 child
->thread
.regs
.regs
.gp
[HOST_EFLAGS
] |= value
;
105 panic("Bad register in putreg(): %d\n", regno
);
108 child
->thread
.regs
.regs
.gp
[reg_offsets
[regno
>> 3]] = value
;
112 int poke_user(struct task_struct
*child
, long addr
, long data
)
114 if ((addr
& 3) || addr
< 0)
117 if (addr
< MAX_REG_OFFSET
)
118 return putreg(child
, addr
, data
);
119 else if ((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
120 (addr
<= offsetof(struct user
, u_debugreg
[7]))) {
121 addr
-= offsetof(struct user
, u_debugreg
[0]);
123 if ((addr
== 4) || (addr
== 5))
125 child
->thread
.arch
.debugregs
[addr
] = data
;
131 unsigned long getreg(struct task_struct
*child
, int regno
)
133 unsigned long mask
= ~0UL;
167 panic("Bad register in getreg: %d\n", regno
);
169 return mask
& child
->thread
.regs
.regs
.gp
[reg_offsets
[regno
>> 3]];
172 int peek_user(struct task_struct
*child
, long addr
, long data
)
174 /* read the word at location addr in the USER area. */
177 if ((addr
& 3) || addr
< 0)
180 tmp
= 0; /* Default return condition */
181 if (addr
< MAX_REG_OFFSET
)
182 tmp
= getreg(child
, addr
);
183 else if ((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
184 (addr
<= offsetof(struct user
, u_debugreg
[7]))) {
185 addr
-= offsetof(struct user
, u_debugreg
[0]);
187 tmp
= child
->thread
.arch
.debugregs
[addr
];
189 return put_user(tmp
, (unsigned long *) data
);
192 long subarch_ptrace(struct task_struct
*child
, long request
,
193 unsigned long addr
, unsigned long data
)
196 void __user
*datap
= (void __user
*) data
;
199 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
200 return copy_regset_to_user(child
, task_user_regset_view(child
),
202 0, sizeof(struct user_i387_struct
),
204 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
205 return copy_regset_from_user(child
, task_user_regset_view(child
),
207 0, sizeof(struct user_i387_struct
),
209 case PTRACE_ARCH_PRCTL
:
210 /* XXX Calls ptrace on the host - needs some SMP thinking */
211 ret
= arch_prctl(child
, data
, (void __user
*) addr
);