File: /usr/src/linux/arch/i386/kernel/ptrace.c
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 */
7
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
17 #include <asm/uaccess.h>
18 #include <asm/pgtable.h>
19 #include <asm/system.h>
20 #include <asm/processor.h>
21 #include <asm/i387.h>
22 #include <asm/debugreg.h>
23
24 /*
25 * does not yet catch signals sent when the child dies.
26 * in exit.c or in signal.c.
27 */
28
29 /* determines which flags the user has access to. */
30 /* 1 = access 0 = no access */
31 #define FLAG_MASK 0x00044dd5
32
33 /* set's the trap flag. */
34 #define TRAP_FLAG 0x100
35
36 /*
37 * Offset of eflags on child stack..
38 */
39 #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
40
41 /*
42 * this routine will get a word off of the processes privileged stack.
43 * the offset is how far from the base addr as stored in the TSS.
44 * this routine assumes that all the privileged stacks are in our
45 * data space.
46 */
47 static inline int get_stack_long(struct task_struct *task, int offset)
48 {
49 unsigned char *stack;
50
51 stack = (unsigned char *)task->thread.esp0;
52 stack += offset;
53 return (*((int *)stack));
54 }
55
56 /*
57 * this routine will put a word on the processes privileged stack.
58 * the offset is how far from the base addr as stored in the TSS.
59 * this routine assumes that all the privileged stacks are in our
60 * data space.
61 */
62 static inline int put_stack_long(struct task_struct *task, int offset,
63 unsigned long data)
64 {
65 unsigned char * stack;
66
67 stack = (unsigned char *) task->thread.esp0;
68 stack += offset;
69 *(unsigned long *) stack = data;
70 return 0;
71 }
72
73 static int putreg(struct task_struct *child,
74 unsigned long regno, unsigned long value)
75 {
76 switch (regno >> 2) {
77 case FS:
78 if (value && (value & 3) != 3)
79 return -EIO;
80 child->thread.fs = value;
81 return 0;
82 case GS:
83 if (value && (value & 3) != 3)
84 return -EIO;
85 child->thread.gs = value;
86 return 0;
87 case DS:
88 case ES:
89 if (value && (value & 3) != 3)
90 return -EIO;
91 value &= 0xffff;
92 break;
93 case SS:
94 case CS:
95 if ((value & 3) != 3)
96 return -EIO;
97 value &= 0xffff;
98 break;
99 case EFL:
100 value &= FLAG_MASK;
101 value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
102 break;
103 }
104 if (regno > GS*4)
105 regno -= 2*4;
106 put_stack_long(child, regno - sizeof(struct pt_regs), value);
107 return 0;
108 }
109
110 static unsigned long getreg(struct task_struct *child,
111 unsigned long regno)
112 {
113 unsigned long retval = ~0UL;
114
115 switch (regno >> 2) {
116 case FS:
117 retval = child->thread.fs;
118 break;
119 case GS:
120 retval = child->thread.gs;
121 break;
122 case DS:
123 case ES:
124 case SS:
125 case CS:
126 retval = 0xffff;
127 /* fall through */
128 default:
129 if (regno > GS*4)
130 regno -= 2*4;
131 regno = regno - sizeof(struct pt_regs);
132 retval &= get_stack_long(child, regno);
133 }
134 return retval;
135 }
136
137 /*
138 * Called by kernel/ptrace.c when detaching..
139 *
140 * Make sure the single step bit is not set.
141 */
142 void ptrace_disable(struct task_struct *child)
143 {
144 long tmp;
145
146 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
147 put_stack_long(child, EFL_OFFSET, tmp);
148 }
149
150 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
151 {
152 struct task_struct *child;
153 struct user * dummy = NULL;
154 int i, ret;
155
156 lock_kernel();
157 ret = -EPERM;
158 if (request == PTRACE_TRACEME) {
159 /* are we already being traced? */
160 if (current->ptrace & PT_PTRACED)
161 goto out;
162 /* set the ptrace bit in the process flags. */
163 current->ptrace |= PT_PTRACED;
164 ret = 0;
165 goto out;
166 }
167 ret = -ESRCH;
168 read_lock(&tasklist_lock);
169 child = find_task_by_pid(pid);
170 if (child)
171 get_task_struct(child);
172 read_unlock(&tasklist_lock);
173 if (!child)
174 goto out;
175
176 ret = -EPERM;
177 if (pid == 1) /* you may not mess with init */
178 goto out_tsk;
179
180 if (request == PTRACE_ATTACH) {
181 ret = ptrace_attach(child);
182 goto out_tsk;
183 }
184 ret = -ESRCH;
185 if (!(child->ptrace & PT_PTRACED))
186 goto out_tsk;
187 if (child->state != TASK_STOPPED) {
188 if (request != PTRACE_KILL)
189 goto out_tsk;
190 }
191 if (child->p_pptr != current)
192 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;
199
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;
206 }
207
208 /* read the word at location addr in the USER area. */
209 case PTRACE_PEEKUSR: {
210 unsigned long tmp;
211
212 ret = -EIO;
213 if ((addr & 3) || addr < 0 ||
214 addr > sizeof(struct user) - 3)
215 break;
216
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];
225 }
226 ret = put_user(tmp,(unsigned long *) data);
227 break;
228 }
229
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;
238
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;
244
245 if (addr < FRAME_SIZE*sizeof(long)) {
246 ret = putreg(child, addr, data);
247 break;
248 }
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. */
253
254 ret = -EIO;
255 if(addr >= (long) &dummy->u_debugreg[0] &&
256 addr <= (long) &dummy->u_debugreg[7]){
257
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;
262
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;
268 }
269
270 addr -= (long) &dummy->u_debugreg;
271 addr = addr >> 2;
272 child->thread.debugreg[addr] = data;
273 ret = 0;
274 }
275 break;
276
277 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
278 case PTRACE_CONT: { /* restart after signal. */
279 long tmp;
280
281 ret = -EIO;
282 if ((unsigned long) data > _NSIG)
283 break;
284 if (request == PTRACE_SYSCALL)
285 child->ptrace |= PT_TRACESYS;
286 else
287 child->ptrace &= ~PT_TRACESYS;
288 child->exit_code = data;
289 /* make sure the single step bit is not set. */
290 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
291 put_stack_long(child, EFL_OFFSET,tmp);
292 wake_up_process(child);
293 ret = 0;
294 break;
295 }
296
297 /*
298 * make the child exit. Best I can do is send it a sigkill.
299 * perhaps it should be put in the status that it wants to
300 * exit.
301 */
302 case PTRACE_KILL: {
303 long tmp;
304
305 ret = 0;
306 if (child->state == TASK_ZOMBIE) /* already dead */
307 break;
308 child->exit_code = SIGKILL;
309 /* make sure the single step bit is not set. */
310 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
311 put_stack_long(child, EFL_OFFSET, tmp);
312 wake_up_process(child);
313 break;
314 }
315
316 case PTRACE_SINGLESTEP: { /* set the trap flag. */
317 long tmp;
318
319 ret = -EIO;
320 if ((unsigned long) data > _NSIG)
321 break;
322 child->ptrace &= ~PT_TRACESYS;
323 if ((child->ptrace & PT_DTRACE) == 0) {
324 /* Spurious delayed TF traps may occur */
325 child->ptrace |= PT_DTRACE;
326 }
327 tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
328 put_stack_long(child, EFL_OFFSET, tmp);
329 child->exit_code = data;
330 /* give it a chance to run. */
331 wake_up_process(child);
332 ret = 0;
333 break;
334 }
335
336 case PTRACE_DETACH:
337 /* detach a process that was attached. */
338 ret = ptrace_detach(child, data);
339 break;
340
341 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
342 if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
343 ret = -EIO;
344 break;
345 }
346 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
347 __put_user(getreg(child, i),(unsigned long *) data);
348 data += sizeof(long);
349 }
350 ret = 0;
351 break;
352 }
353
354 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
355 unsigned long tmp;
356 if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
357 ret = -EIO;
358 break;
359 }
360 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
361 __get_user(tmp, (unsigned long *) data);
362 putreg(child, i, tmp);
363 data += sizeof(long);
364 }
365 ret = 0;
366 break;
367 }
368
369 case PTRACE_GETFPREGS: { /* Get the child FPU state. */
370 if (!access_ok(VERIFY_WRITE, (unsigned *)data,
371 sizeof(struct user_i387_struct))) {
372 ret = -EIO;
373 break;
374 }
375 ret = 0;
376 if ( !child->used_math ) {
377 /* Simulate an empty FPU. */
378 set_fpu_cwd(child, 0x037f);
379 set_fpu_swd(child, 0x0000);
380 set_fpu_twd(child, 0xffff);
381 }
382 get_fpregs((struct user_i387_struct *)data, child);
383 break;
384 }
385
386 case PTRACE_SETFPREGS: { /* Set the child FPU state. */
387 if (!access_ok(VERIFY_READ, (unsigned *)data,
388 sizeof(struct user_i387_struct))) {
389 ret = -EIO;
390 break;
391 }
392 child->used_math = 1;
393 set_fpregs(child, (struct user_i387_struct *)data);
394 ret = 0;
395 break;
396 }
397
398 case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
399 if (!access_ok(VERIFY_WRITE, (unsigned *)data,
400 sizeof(struct user_fxsr_struct))) {
401 ret = -EIO;
402 break;
403 }
404 if ( !child->used_math ) {
405 /* Simulate an empty FPU. */
406 set_fpu_cwd(child, 0x037f);
407 set_fpu_swd(child, 0x0000);
408 set_fpu_twd(child, 0xffff);
409 set_fpu_mxcsr(child, 0x1f80);
410 }
411 ret = get_fpxregs((struct user_fxsr_struct *)data, child);
412 break;
413 }
414
415 case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
416 if (!access_ok(VERIFY_READ, (unsigned *)data,
417 sizeof(struct user_fxsr_struct))) {
418 ret = -EIO;
419 break;
420 }
421 child->used_math = 1;
422 ret = set_fpxregs(child, (struct user_fxsr_struct *)data);
423 break;
424 }
425
426 case PTRACE_SETOPTIONS: {
427 if (data & PTRACE_O_TRACESYSGOOD)
428 child->ptrace |= PT_TRACESYSGOOD;
429 else
430 child->ptrace &= ~PT_TRACESYSGOOD;
431 ret = 0;
432 break;
433 }
434
435 default:
436 ret = -EIO;
437 break;
438 }
439 out_tsk:
440 free_task_struct(child);
441 out:
442 unlock_kernel();
443 return ret;
444 }
445
446 asmlinkage void syscall_trace(void)
447 {
448 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
449 (PT_PTRACED|PT_TRACESYS))
450 return;
451 /* the 0x80 provides a way for the tracing parent to distinguish
452 between a syscall stop and SIGTRAP delivery */
453 current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
454 ? 0x80 : 0);
455 current->state = TASK_STOPPED;
456 notify_parent(current, SIGCHLD);
457 schedule();
458 /*
459 * this isn't the same as continuing with a signal, but it will do
460 * for normal use. strace only continues with a signal if the
461 * stopping signal is not SIGTRAP. -brl
462 */
463 if (current->exit_code) {
464 send_sig(current->exit_code, current, 1);
465 current->exit_code = 0;
466 }
467 }
468