Merge with Linux 2.5.48.
[linux-2.6/linux-mips.git] / arch / i386 / kernel / ptrace.c
blobff43c54febdae97e0b47a39e49347b3f5ea5eafb
1 /* ptrace.c */
2 /* By Ross Biro 1/23/92 */
3 /*
4 * Pentium III FXSR, SSE support
5 * Gareth Hughes <gareth@valinux.com>, May 2000
6 */
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
10 #include <linux/mm.h>
11 #include <linux/smp.h>
12 #include <linux/smp_lock.h>
13 #include <linux/errno.h>
14 #include <linux/ptrace.h>
15 #include <linux/user.h>
16 #include <linux/security.h>
18 #include <asm/uaccess.h>
19 #include <asm/pgtable.h>
20 #include <asm/system.h>
21 #include <asm/processor.h>
22 #include <asm/i387.h>
23 #include <asm/debugreg.h>
26 * does not yet catch signals sent when the child dies.
27 * in exit.c or in signal.c.
30 /* determines which flags the user has access to. */
31 /* 1 = access 0 = no access */
32 #define FLAG_MASK 0x00044dd5
34 /* set's the trap flag. */
35 #define TRAP_FLAG 0x100
38 * Offset of eflags on child stack..
40 #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
43 * this routine will get a word off of the processes privileged stack.
44 * the offset is how far from the base addr as stored in the TSS.
45 * this routine assumes that all the privileged stacks are in our
46 * data space.
47 */
48 static inline int get_stack_long(struct task_struct *task, int offset)
50 unsigned char *stack;
52 stack = (unsigned char *)task->thread.esp0;
53 stack += offset;
54 return (*((int *)stack));
58 * this routine will put a word on the processes privileged stack.
59 * the offset is how far from the base addr as stored in the TSS.
60 * this routine assumes that all the privileged stacks are in our
61 * data space.
63 static inline int put_stack_long(struct task_struct *task, int offset,
64 unsigned long data)
66 unsigned char * stack;
68 stack = (unsigned char *) task->thread.esp0;
69 stack += offset;
70 *(unsigned long *) stack = data;
71 return 0;
74 static int putreg(struct task_struct *child,
75 unsigned long regno, unsigned long value)
77 switch (regno >> 2) {
78 case FS:
79 if (value && (value & 3) != 3)
80 return -EIO;
81 child->thread.fs = value;
82 return 0;
83 case GS:
84 if (value && (value & 3) != 3)
85 return -EIO;
86 child->thread.gs = value;
87 return 0;
88 case DS:
89 case ES:
90 if (value && (value & 3) != 3)
91 return -EIO;
92 value &= 0xffff;
93 break;
94 case SS:
95 case CS:
96 if ((value & 3) != 3)
97 return -EIO;
98 value &= 0xffff;
99 break;
100 case EFL:
101 value &= FLAG_MASK;
102 value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
103 break;
105 if (regno > GS*4)
106 regno -= 2*4;
107 put_stack_long(child, regno - sizeof(struct pt_regs), value);
108 return 0;
111 static unsigned long getreg(struct task_struct *child,
112 unsigned long regno)
114 unsigned long retval = ~0UL;
116 switch (regno >> 2) {
117 case FS:
118 retval = child->thread.fs;
119 break;
120 case GS:
121 retval = child->thread.gs;
122 break;
123 case DS:
124 case ES:
125 case SS:
126 case CS:
127 retval = 0xffff;
128 /* fall through */
129 default:
130 if (regno > GS*4)
131 regno -= 2*4;
132 regno = regno - sizeof(struct pt_regs);
133 retval &= get_stack_long(child, regno);
135 return retval;
139 * Called by kernel/ptrace.c when detaching..
141 * Make sure the single step bit is not set.
143 void ptrace_disable(struct task_struct *child)
145 long tmp;
147 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
148 put_stack_long(child, EFL_OFFSET, tmp);
151 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
153 struct task_struct *child;
154 struct user * dummy = NULL;
155 int i, ret;
157 lock_kernel();
158 ret = -EPERM;
159 if (request == PTRACE_TRACEME) {
160 /* are we already being traced? */
161 if (current->ptrace & PT_PTRACED)
162 goto out;
163 ret = security_ops->ptrace(current->parent, current);
164 if (ret)
165 goto out;
166 /* set the ptrace bit in the process flags. */
167 current->ptrace |= PT_PTRACED;
168 ret = 0;
169 goto out;
171 ret = -ESRCH;
172 read_lock(&tasklist_lock);
173 child = find_task_by_pid(pid);
174 if (child)
175 get_task_struct(child);
176 read_unlock(&tasklist_lock);
177 if (!child)
178 goto out;
180 ret = -EPERM;
181 if (pid == 1) /* you may not mess with init */
182 goto out_tsk;
184 if (request == PTRACE_ATTACH) {
185 ret = ptrace_attach(child);
186 goto out_tsk;
189 ret = ptrace_check_attach(child, request == PTRACE_KILL);
190 if (ret < 0)
191 goto out_tsk;
193 switch (request) {
194 /* when I and D space are separate, these will need to be fixed. */
195 case PTRACE_PEEKTEXT: /* read word at location addr. */
196 case PTRACE_PEEKDATA: {
197 unsigned long tmp;
198 int copied;
200 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
201 ret = -EIO;
202 if (copied != sizeof(tmp))
203 break;
204 ret = put_user(tmp,(unsigned long *) data);
205 break;
208 /* read the word at location addr in the USER area. */
209 case PTRACE_PEEKUSR: {
210 unsigned long tmp;
212 ret = -EIO;
213 if ((addr & 3) || addr < 0 ||
214 addr > sizeof(struct user) - 3)
215 break;
217 tmp = 0; /* Default return condition */
218 if(addr < FRAME_SIZE*sizeof(long))
219 tmp = getreg(child, addr);
220 if(addr >= (long) &dummy->u_debugreg[0] &&
221 addr <= (long) &dummy->u_debugreg[7]){
222 addr -= (long) &dummy->u_debugreg[0];
223 addr = addr >> 2;
224 tmp = child->thread.debugreg[addr];
226 ret = put_user(tmp,(unsigned long *) data);
227 break;
230 /* when I and D space are separate, this will have to be fixed. */
231 case PTRACE_POKETEXT: /* write the word at location addr. */
232 case PTRACE_POKEDATA:
233 ret = 0;
234 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
235 break;
236 ret = -EIO;
237 break;
239 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
240 ret = -EIO;
241 if ((addr & 3) || addr < 0 ||
242 addr > sizeof(struct user) - 3)
243 break;
245 if (addr < FRAME_SIZE*sizeof(long)) {
246 ret = putreg(child, addr, data);
247 break;
249 /* We need to be very careful here. We implicitly
250 want to modify a portion of the task_struct, and we
251 have to be selective about what portions we allow someone
252 to modify. */
254 ret = -EIO;
255 if(addr >= (long) &dummy->u_debugreg[0] &&
256 addr <= (long) &dummy->u_debugreg[7]){
258 if(addr == (long) &dummy->u_debugreg[4]) break;
259 if(addr == (long) &dummy->u_debugreg[5]) break;
260 if(addr < (long) &dummy->u_debugreg[4] &&
261 ((unsigned long) data) >= TASK_SIZE-3) break;
263 if(addr == (long) &dummy->u_debugreg[7]) {
264 data &= ~DR_CONTROL_RESERVED;
265 for(i=0; i<4; i++)
266 if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
267 goto out_tsk;
270 addr -= (long) &dummy->u_debugreg;
271 addr = addr >> 2;
272 child->thread.debugreg[addr] = data;
273 ret = 0;
275 break;
277 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
278 case PTRACE_CONT: { /* restart after signal. */
279 long tmp;
281 ret = -EIO;
282 if ((unsigned long) data > _NSIG)
283 break;
284 if (request == PTRACE_SYSCALL) {
285 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
287 else {
288 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
290 child->exit_code = data;
291 /* make sure the single step bit is not set. */
292 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
293 put_stack_long(child, EFL_OFFSET,tmp);
294 wake_up_process(child);
295 ret = 0;
296 break;
300 * make the child exit. Best I can do is send it a sigkill.
301 * perhaps it should be put in the status that it wants to
302 * exit.
304 case PTRACE_KILL: {
305 long tmp;
307 ret = 0;
308 if (child->state == TASK_ZOMBIE) /* already dead */
309 break;
310 child->exit_code = SIGKILL;
311 /* make sure the single step bit is not set. */
312 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
313 put_stack_long(child, EFL_OFFSET, tmp);
314 wake_up_process(child);
315 break;
318 case PTRACE_SINGLESTEP: { /* set the trap flag. */
319 long tmp;
321 ret = -EIO;
322 if ((unsigned long) data > _NSIG)
323 break;
324 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
325 if ((child->ptrace & PT_DTRACE) == 0) {
326 /* Spurious delayed TF traps may occur */
327 child->ptrace |= PT_DTRACE;
329 tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
330 put_stack_long(child, EFL_OFFSET, tmp);
331 child->exit_code = data;
332 /* give it a chance to run. */
333 wake_up_process(child);
334 ret = 0;
335 break;
338 case PTRACE_DETACH:
339 /* detach a process that was attached. */
340 ret = ptrace_detach(child, data);
341 break;
343 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
344 if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
345 ret = -EIO;
346 break;
348 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
349 __put_user(getreg(child, i),(unsigned long *) data);
350 data += sizeof(long);
352 ret = 0;
353 break;
356 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
357 unsigned long tmp;
358 if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
359 ret = -EIO;
360 break;
362 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
363 __get_user(tmp, (unsigned long *) data);
364 putreg(child, i, tmp);
365 data += sizeof(long);
367 ret = 0;
368 break;
371 case PTRACE_GETFPREGS: { /* Get the child FPU state. */
372 if (!access_ok(VERIFY_WRITE, (unsigned *)data,
373 sizeof(struct user_i387_struct))) {
374 ret = -EIO;
375 break;
377 ret = 0;
378 if (!child->used_math)
379 init_fpu(child);
380 get_fpregs((struct user_i387_struct *)data, child);
381 break;
384 case PTRACE_SETFPREGS: { /* Set the child FPU state. */
385 if (!access_ok(VERIFY_READ, (unsigned *)data,
386 sizeof(struct user_i387_struct))) {
387 ret = -EIO;
388 break;
390 child->used_math = 1;
391 set_fpregs(child, (struct user_i387_struct *)data);
392 ret = 0;
393 break;
396 case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
397 if (!access_ok(VERIFY_WRITE, (unsigned *)data,
398 sizeof(struct user_fxsr_struct))) {
399 ret = -EIO;
400 break;
402 if (!child->used_math)
403 init_fpu(child);
404 ret = get_fpxregs((struct user_fxsr_struct *)data, child);
405 break;
408 case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
409 if (!access_ok(VERIFY_READ, (unsigned *)data,
410 sizeof(struct user_fxsr_struct))) {
411 ret = -EIO;
412 break;
414 child->used_math = 1;
415 ret = set_fpxregs(child, (struct user_fxsr_struct *)data);
416 break;
419 default:
420 ret = ptrace_request(child, request, addr, data);
421 break;
423 out_tsk:
424 put_task_struct(child);
425 out:
426 unlock_kernel();
427 return ret;
430 /* notification of system call entry/exit
431 * - triggered by current->work.syscall_trace
433 __attribute__((regparm(3)))
434 void do_syscall_trace(struct pt_regs *regs, int entryexit)
436 if (!test_thread_flag(TIF_SYSCALL_TRACE))
437 return;
438 if (!(current->ptrace & PT_PTRACED))
439 return;
440 /* the 0x80 provides a way for the tracing parent to distinguish
441 between a syscall stop and SIGTRAP delivery */
442 current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
443 ? 0x80 : 0);
444 current->state = TASK_STOPPED;
445 notify_parent(current, SIGCHLD);
446 schedule();
448 * this isn't the same as continuing with a signal, but it will do
449 * for normal use. strace only continues with a signal if the
450 * stopping signal is not SIGTRAP. -brl
452 if (current->exit_code) {
453 send_sig(current->exit_code, current, 1);
454 current->exit_code = 0;