ebd4dd6ef73b0e09a7fc70d8e605354be67a61cb
[cascardo/linux.git] / arch / x86 / um / ptrace_32.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include <linux/mm.h>
7 #include <linux/sched.h>
8 #include <asm/uaccess.h>
9 #include <asm/ptrace-abi.h>
10 #include <skas.h>
11
12 extern int arch_switch_tls(struct task_struct *to);
13
14 void arch_switch_to(struct task_struct *to)
15 {
16         int err = arch_switch_tls(to);
17         if (!err)
18                 return;
19
20         if (err != -EINVAL)
21                 printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
22                        "not EINVAL\n", -err);
23         else
24                 printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
25 }
26
27 int is_syscall(unsigned long addr)
28 {
29         unsigned short instr;
30         int n;
31
32         n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
33         if (n) {
34                 /* access_process_vm() grants access to vsyscall and stub,
35                  * while copy_from_user doesn't. Maybe access_process_vm is
36                  * slow, but that doesn't matter, since it will be called only
37                  * in case of singlestepping, if copy_from_user failed.
38                  */
39                 n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
40                 if (n != sizeof(instr)) {
41                         printk(KERN_ERR "is_syscall : failed to read "
42                                "instruction from 0x%lx\n", addr);
43                         return 1;
44                 }
45         }
46         /* int 0x80 or sysenter */
47         return (instr == 0x80cd) || (instr == 0x340f);
48 }
49
50 /* determines which flags the user has access to. */
51 /* 1 = access 0 = no access */
52 #define FLAG_MASK 0x00044dd5
53
54 static const int reg_offsets[] = {
55         [EBX] = HOST_BX,
56         [ECX] = HOST_CX,
57         [EDX] = HOST_DX,
58         [ESI] = HOST_SI,
59         [EDI] = HOST_DI,
60         [EBP] = HOST_BP,
61         [EAX] = HOST_AX,
62         [DS] = HOST_DS,
63         [ES] = HOST_ES,
64         [FS] = HOST_FS,
65         [GS] = HOST_GS,
66         [EIP] = HOST_IP,
67         [CS] = HOST_CS,
68         [EFL] = HOST_EFLAGS,
69         [UESP] = HOST_SP,
70         [SS] = HOST_SS,
71         [ORIG_EAX] = HOST_ORIG_AX,
72 };
73
74 int putreg(struct task_struct *child, int regno, unsigned long value)
75 {
76         regno >>= 2;
77         switch (regno) {
78         case EBX:
79         case ECX:
80         case EDX:
81         case ESI:
82         case EDI:
83         case EBP:
84         case EAX:
85         case EIP:
86         case UESP:
87         case ORIG_EAX:
88                 break;
89         case FS:
90                 if (value && (value & 3) != 3)
91                         return -EIO;
92                 break;
93         case GS:
94                 if (value && (value & 3) != 3)
95                         return -EIO;
96                 break;
97         case DS:
98         case ES:
99                 if (value && (value & 3) != 3)
100                         return -EIO;
101                 value &= 0xffff;
102                 break;
103         case SS:
104         case CS:
105                 if ((value & 3) != 3)
106                         return -EIO;
107                 value &= 0xffff;
108                 break;
109         case EFL:
110                 value &= FLAG_MASK;
111                 child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
112                 return 0;
113         default :
114                 panic("Bad register in putreg() : %d\n", regno);
115         }
116         child->thread.regs.regs.gp[reg_offsets[regno]] = value;
117         return 0;
118 }
119
120 int poke_user(struct task_struct *child, long addr, long data)
121 {
122         if ((addr & 3) || addr < 0)
123                 return -EIO;
124
125         if (addr < MAX_REG_OFFSET)
126                 return putreg(child, addr, data);
127         else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
128                  (addr <= offsetof(struct user, u_debugreg[7]))) {
129                 addr -= offsetof(struct user, u_debugreg[0]);
130                 addr = addr >> 2;
131                 if ((addr == 4) || (addr == 5))
132                         return -EIO;
133                 child->thread.arch.debugregs[addr] = data;
134                 return 0;
135         }
136         return -EIO;
137 }
138
139 unsigned long getreg(struct task_struct *child, int regno)
140 {
141         unsigned long mask = ~0UL;
142
143         regno >>= 2;
144         switch (regno) {
145         case FS:
146         case GS:
147         case DS:
148         case ES:
149         case SS:
150         case CS:
151                 mask = 0xffff;
152                 break;
153         case EIP:
154         case UESP:
155         case EAX:
156         case EBX:
157         case ECX:
158         case EDX:
159         case ESI:
160         case EDI:
161         case EBP:
162         case EFL:
163         case ORIG_EAX:
164                 break;
165         default:
166                 panic("Bad register in getreg() : %d\n", regno);
167         }
168         return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
169 }
170
171 /* read the word at location addr in the USER area. */
172 int peek_user(struct task_struct *child, long addr, long data)
173 {
174         unsigned long tmp;
175
176         if ((addr & 3) || addr < 0)
177                 return -EIO;
178
179         tmp = 0;  /* Default return condition */
180         if (addr < MAX_REG_OFFSET) {
181                 tmp = getreg(child, addr);
182         }
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]);
186                 addr = addr >> 2;
187                 tmp = child->thread.arch.debugregs[addr];
188         }
189         return put_user(tmp, (unsigned long __user *) data);
190 }
191
192 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
193 {
194         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
195         struct user_i387_struct fpregs;
196
197         err = save_i387_registers(userspace_pid[cpu],
198                                   (unsigned long *) &fpregs);
199         if (err)
200                 return err;
201
202         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
203         if(n > 0)
204                 return -EFAULT;
205
206         return n;
207 }
208
209 static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
210 {
211         int n, cpu = ((struct thread_info *) child->stack)->cpu;
212         struct user_i387_struct fpregs;
213
214         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
215         if (n > 0)
216                 return -EFAULT;
217
218         return restore_i387_registers(userspace_pid[cpu],
219                                     (unsigned long *) &fpregs);
220 }
221
222 static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
223 {
224         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
225         struct user_fxsr_struct fpregs;
226
227         err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
228         if (err)
229                 return err;
230
231         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
232         if(n > 0)
233                 return -EFAULT;
234
235         return n;
236 }
237
238 static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
239 {
240         int n, cpu = ((struct thread_info *) child->stack)->cpu;
241         struct user_fxsr_struct fpregs;
242
243         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
244         if (n > 0)
245                 return -EFAULT;
246
247         return restore_fpx_registers(userspace_pid[cpu],
248                                      (unsigned long *) &fpregs);
249 }
250
251 long subarch_ptrace(struct task_struct *child, long request,
252                     unsigned long addr, unsigned long data)
253 {
254         int ret = -EIO;
255         void __user *datap = (void __user *) data;
256         switch (request) {
257         case PTRACE_GETFPREGS: /* Get the child FPU state. */
258                 ret = get_fpregs(datap, child);
259                 break;
260         case PTRACE_SETFPREGS: /* Set the child FPU state. */
261                 ret = set_fpregs(datap, child);
262                 break;
263         case PTRACE_GETFPXREGS: /* Get the child FPU state. */
264                 ret = get_fpxregs(datap, child);
265                 break;
266         case PTRACE_SETFPXREGS: /* Set the child FPU state. */
267                 ret = set_fpxregs(datap, child);
268                 break;
269         default:
270                 ret = -EIO;
271         }
272         return ret;
273 }