2 /* By Ross Biro 1/23/92 */
3 /* edited by Linus Torvalds */
5 #include <linux/config.h> /* for CONFIG_MATH_EMULATION */
6 #include <linux/kernel.h>
7 #include <linux/sched.h>
10 #include <linux/smp_lock.h>
11 #include <linux/errno.h>
12 #include <linux/ptrace.h>
13 #include <linux/user.h>
15 #include <asm/uaccess.h>
16 #include <asm/pgtable.h>
17 #include <asm/system.h>
18 #include <asm/processor.h>
19 #include <asm/debugreg.h>
22 * does not yet catch signals sent when the child dies.
23 * in exit.c or in signal.c.
26 /* determines which flags the user has access to. */
27 /* 1 = access 0 = no access */
28 #define FLAG_MASK 0x00044dd5
30 /* set's the trap flag. */
31 #define TRAP_FLAG 0x100
34 * Offset of eflags on child stack..
36 #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
39 * this routine will get a word off of the processes privileged stack.
40 * the offset is how far from the base addr as stored in the TSS.
41 * this routine assumes that all the privileged stacks are in our
44 static inline int get_stack_long(struct task_struct
*task
, int offset
)
48 stack
= (unsigned char *)task
->thread
.esp0
;
50 return (*((int *)stack
));
54 * this routine will put a word on the processes privileged stack.
55 * the offset is how far from the base addr as stored in the TSS.
56 * this routine assumes that all the privileged stacks are in our
59 static inline int put_stack_long(struct task_struct
*task
, int offset
,
62 unsigned char * stack
;
64 stack
= (unsigned char *) task
->thread
.esp0
;
66 *(unsigned long *) stack
= data
;
70 static int putreg(struct task_struct
*child
,
71 unsigned long regno
, unsigned long value
)
75 if (value
&& (value
& 3) != 3)
77 child
->thread
.fs
= value
;
80 if (value
&& (value
& 3) != 3)
82 child
->thread
.gs
= value
;
86 if (value
&& (value
& 3) != 3)
98 value
|= get_stack_long(child
, EFL_OFFSET
) & ~FLAG_MASK
;
102 put_stack_long(child
, regno
- sizeof(struct pt_regs
), value
);
106 static unsigned long getreg(struct task_struct
*child
,
109 unsigned long retval
= ~0UL;
111 switch (regno
>> 2) {
113 retval
= child
->thread
.fs
;
116 retval
= child
->thread
.gs
;
127 regno
= regno
- sizeof(struct pt_regs
);
128 retval
&= get_stack_long(child
, regno
);
133 asmlinkage
int sys_ptrace(long request
, long pid
, long addr
, long data
)
135 struct task_struct
*child
;
136 struct user
* dummy
= NULL
;
142 if (request
== PTRACE_TRACEME
) {
143 /* are we already being traced? */
144 if (current
->flags
& PF_PTRACED
)
146 /* set the ptrace bit in the process flags. */
147 current
->flags
|= PF_PTRACED
;
152 read_lock(&tasklist_lock
);
153 child
= find_task_by_pid(pid
);
154 read_unlock(&tasklist_lock
); /* FIXME!!! */
158 if (pid
== 1) /* you may not mess with init */
160 if (request
== PTRACE_ATTACH
) {
161 if (child
== current
)
163 if ((!child
->dumpable
||
164 (current
->uid
!= child
->euid
) ||
165 (current
->uid
!= child
->suid
) ||
166 (current
->uid
!= child
->uid
) ||
167 (current
->gid
!= child
->egid
) ||
168 (current
->gid
!= child
->sgid
) ||
169 (!cap_issubset(child
->cap_permitted
, current
->cap_permitted
)) ||
170 (current
->gid
!= child
->gid
)) && !capable(CAP_SYS_PTRACE
))
172 /* the same process cannot be attached many times */
173 if (child
->flags
& PF_PTRACED
)
175 child
->flags
|= PF_PTRACED
;
177 write_lock_irqsave(&tasklist_lock
, flags
);
178 if (child
->p_pptr
!= current
) {
180 child
->p_pptr
= current
;
183 write_unlock_irqrestore(&tasklist_lock
, flags
);
185 send_sig(SIGSTOP
, child
, 1);
190 if (!(child
->flags
& PF_PTRACED
))
192 if (child
->state
!= TASK_STOPPED
) {
193 if (request
!= PTRACE_KILL
)
196 if (child
->p_pptr
!= current
)
200 /* when I and D space are separate, these will need to be fixed. */
201 case PTRACE_PEEKTEXT
: /* read word at location addr. */
202 case PTRACE_PEEKDATA
: {
206 copied
= access_process_vm(child
, addr
, &tmp
, sizeof(tmp
), 0);
208 if (copied
!= sizeof(tmp
))
210 ret
= put_user(tmp
,(unsigned long *) data
);
214 /* read the word at location addr in the USER area. */
215 case PTRACE_PEEKUSR
: {
219 if ((addr
& 3) || addr
< 0 ||
220 addr
> sizeof(struct user
) - 3)
223 tmp
= 0; /* Default return condition */
224 if(addr
< 17*sizeof(long))
225 tmp
= getreg(child
, addr
);
226 if(addr
>= (long) &dummy
->u_debugreg
[0] &&
227 addr
<= (long) &dummy
->u_debugreg
[7]){
228 addr
-= (long) &dummy
->u_debugreg
[0];
230 tmp
= child
->thread
.debugreg
[addr
];
232 ret
= put_user(tmp
,(unsigned long *) data
);
236 /* when I and D space are separate, this will have to be fixed. */
237 case PTRACE_POKETEXT
: /* write the word at location addr. */
238 case PTRACE_POKEDATA
:
240 if (access_process_vm(child
, addr
, &data
, sizeof(data
), 1) == sizeof(data
))
245 case PTRACE_POKEUSR
: /* write the word at location addr in the USER area */
247 if ((addr
& 3) || addr
< 0 ||
248 addr
> sizeof(struct user
) - 3)
251 if (addr
< 17*sizeof(long)) {
252 ret
= putreg(child
, addr
, data
);
255 /* We need to be very careful here. We implicitly
256 want to modify a portion of the task_struct, and we
257 have to be selective about what portions we allow someone
261 if(addr
>= (long) &dummy
->u_debugreg
[0] &&
262 addr
<= (long) &dummy
->u_debugreg
[7]){
264 if(addr
== (long) &dummy
->u_debugreg
[4]) break;
265 if(addr
== (long) &dummy
->u_debugreg
[5]) break;
266 if(addr
< (long) &dummy
->u_debugreg
[4] &&
267 ((unsigned long) data
) >= TASK_SIZE
-3) break;
269 if(addr
== (long) &dummy
->u_debugreg
[7]) {
270 data
&= ~DR_CONTROL_RESERVED
;
272 if ((0x5f54 >> ((data
>> (16 + 4*i
)) & 0xf)) & 1)
276 addr
-= (long) &dummy
->u_debugreg
;
278 child
->thread
.debugreg
[addr
] = data
;
283 case PTRACE_SYSCALL
: /* continue and stop at next (return from) syscall */
284 case PTRACE_CONT
: { /* restart after signal. */
288 if ((unsigned long) data
> _NSIG
)
290 if (request
== PTRACE_SYSCALL
)
291 child
->flags
|= PF_TRACESYS
;
293 child
->flags
&= ~PF_TRACESYS
;
294 child
->exit_code
= data
;
295 /* make sure the single step bit is not set. */
296 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
297 put_stack_long(child
, EFL_OFFSET
,tmp
);
298 wake_up_process(child
);
304 * make the child exit. Best I can do is send it a sigkill.
305 * perhaps it should be put in the status that it wants to
312 if (child
->state
== TASK_ZOMBIE
) /* already dead */
314 child
->exit_code
= SIGKILL
;
315 /* make sure the single step bit is not set. */
316 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
317 put_stack_long(child
, EFL_OFFSET
, tmp
);
318 wake_up_process(child
);
322 case PTRACE_SINGLESTEP
: { /* set the trap flag. */
326 if ((unsigned long) data
> _NSIG
)
328 child
->flags
&= ~PF_TRACESYS
;
329 if ((child
->flags
& PF_DTRACE
) == 0) {
330 /* Spurious delayed TF traps may occur */
331 child
->flags
|= PF_DTRACE
;
333 tmp
= get_stack_long(child
, EFL_OFFSET
) | TRAP_FLAG
;
334 put_stack_long(child
, EFL_OFFSET
, tmp
);
335 child
->exit_code
= data
;
336 /* give it a chance to run. */
337 wake_up_process(child
);
342 case PTRACE_DETACH
: { /* detach a process that was attached. */
346 if ((unsigned long) data
> _NSIG
)
348 child
->flags
&= ~(PF_PTRACED
|PF_TRACESYS
);
349 child
->exit_code
= data
;
350 write_lock_irqsave(&tasklist_lock
, flags
);
352 child
->p_pptr
= child
->p_opptr
;
354 write_unlock_irqrestore(&tasklist_lock
, flags
);
355 /* make sure the single step bit is not set. */
356 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
357 put_stack_long(child
, EFL_OFFSET
, tmp
);
358 wake_up_process(child
);
363 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
364 if (!access_ok(VERIFY_WRITE
, (unsigned *)data
, 17*sizeof(long))) {
368 for ( i
= 0; i
< 17*sizeof(long); i
+= sizeof(long) ) {
369 __put_user(getreg(child
, i
),(unsigned long *) data
);
370 data
+= sizeof(long);
376 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
378 if (!access_ok(VERIFY_READ
, (unsigned *)data
, 17*sizeof(long))) {
382 for ( i
= 0; i
< 17*sizeof(long); i
+= sizeof(long) ) {
383 __get_user(tmp
, (unsigned long *) data
);
384 putreg(child
, i
, tmp
);
385 data
+= sizeof(long);
391 case PTRACE_GETFPREGS
: { /* Get the child FPU state. */
392 if (!access_ok(VERIFY_WRITE
, (unsigned *)data
, sizeof(struct user_i387_struct
))) {
397 if ( !child
->used_math
) {
398 /* Simulate an empty FPU. */
399 child
->thread
.i387
.hard
.cwd
= 0xffff037f;
400 child
->thread
.i387
.hard
.swd
= 0xffff0000;
401 child
->thread
.i387
.hard
.twd
= 0xffffffff;
403 #ifdef CONFIG_MATH_EMULATION
404 if ( boot_cpu_data
.hard_math
) {
406 __copy_to_user((void *)data
, &child
->thread
.i387
.hard
, sizeof(struct user_i387_struct
));
407 #ifdef CONFIG_MATH_EMULATION
409 save_i387_soft(&child
->thread
.i387
.soft
, (struct _fpstate
*)data
);
415 case PTRACE_SETFPREGS
: { /* Set the child FPU state. */
416 if (!access_ok(VERIFY_READ
, (unsigned *)data
, sizeof(struct user_i387_struct
))) {
420 child
->used_math
= 1;
421 #ifdef CONFIG_MATH_EMULATION
422 if ( boot_cpu_data
.hard_math
) {
424 __copy_from_user(&child
->thread
.i387
.hard
, (void *)data
, sizeof(struct user_i387_struct
));
425 #ifdef CONFIG_MATH_EMULATION
427 restore_i387_soft(&child
->thread
.i387
.soft
, (struct _fpstate
*)data
);
443 asmlinkage
void syscall_trace(void)
445 if ((current
->flags
& (PF_PTRACED
|PF_TRACESYS
))
446 != (PF_PTRACED
|PF_TRACESYS
))
448 current
->exit_code
= SIGTRAP
;
449 current
->state
= TASK_STOPPED
;
450 notify_parent(current
, SIGCHLD
);
453 * this isn't the same as continuing with a signal, but it will do
454 * for normal use. strace only continues with a signal if the
455 * stopping signal is not SIGTRAP. -brl
457 if (current
->exit_code
) {
458 send_sig(current
->exit_code
, current
, 1);
459 current
->exit_code
= 0;