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
)
77 if (value
&& (value
& 3) != 3)
79 child
->thread
.fs
= value
;
82 if (value
&& (value
& 3) != 3)
84 child
->thread
.gs
= value
;
88 if (value
&& (value
& 3) != 3)
100 value
|= get_stack_long(child
, EFL_OFFSET
) & ~FLAG_MASK
;
104 put_stack_long(child
, regno
- sizeof(struct pt_regs
), value
);
108 static unsigned long getreg(struct task_struct
*child
,
111 unsigned long retval
= ~0UL;
113 switch (regno
>> 2) {
115 retval
= child
->thread
.fs
;
118 retval
= child
->thread
.gs
;
129 regno
= regno
- sizeof(struct pt_regs
);
130 retval
&= get_stack_long(child
, regno
);
135 asmlinkage
int sys_ptrace(long request
, long pid
, long addr
, long data
)
137 struct task_struct
*child
;
138 struct user
* dummy
= NULL
;
144 if (request
== PTRACE_TRACEME
) {
145 /* are we already being traced? */
146 if (current
->flags
& PF_PTRACED
)
148 /* set the ptrace bit in the process flags. */
149 current
->flags
|= PF_PTRACED
;
154 read_lock(&tasklist_lock
);
155 child
= find_task_by_pid(pid
);
156 read_unlock(&tasklist_lock
); /* FIXME!!! */
160 if (pid
== 1) /* you may not mess with init */
162 if (request
== PTRACE_ATTACH
) {
163 if (child
== current
)
165 if ((!child
->dumpable
||
166 (current
->uid
!= child
->euid
) ||
167 (current
->uid
!= child
->suid
) ||
168 (current
->uid
!= child
->uid
) ||
169 (current
->gid
!= child
->egid
) ||
170 (current
->gid
!= child
->sgid
) ||
171 (!cap_issubset(child
->cap_permitted
, current
->cap_permitted
)) ||
172 (current
->gid
!= child
->gid
)) && !capable(CAP_SYS_PTRACE
))
174 /* the same process cannot be attached many times */
175 if (child
->flags
& PF_PTRACED
)
177 child
->flags
|= PF_PTRACED
;
179 write_lock_irqsave(&tasklist_lock
, flags
);
180 if (child
->p_pptr
!= current
) {
182 child
->p_pptr
= current
;
185 write_unlock_irqrestore(&tasklist_lock
, flags
);
187 send_sig(SIGSTOP
, child
, 1);
192 if (!(child
->flags
& PF_PTRACED
))
194 if (child
->state
!= TASK_STOPPED
) {
195 if (request
!= PTRACE_KILL
)
198 if (child
->p_pptr
!= current
)
202 /* when I and D space are separate, these will need to be fixed. */
203 case PTRACE_PEEKTEXT
: /* read word at location addr. */
204 case PTRACE_PEEKDATA
: {
208 copied
= access_process_vm(child
, addr
, &tmp
, sizeof(tmp
), 0);
210 if (copied
!= sizeof(tmp
))
212 ret
= put_user(tmp
,(unsigned long *) data
);
216 /* read the word at location addr in the USER area. */
217 case PTRACE_PEEKUSR
: {
221 if ((addr
& 3) || addr
< 0 ||
222 addr
> sizeof(struct user
) - 3)
225 tmp
= 0; /* Default return condition */
226 if(addr
< 17*sizeof(long))
227 tmp
= getreg(child
, addr
);
228 if(addr
>= (long) &dummy
->u_debugreg
[0] &&
229 addr
<= (long) &dummy
->u_debugreg
[7]){
230 addr
-= (long) &dummy
->u_debugreg
[0];
232 tmp
= child
->thread
.debugreg
[addr
];
234 ret
= put_user(tmp
,(unsigned long *) data
);
238 /* when I and D space are separate, this will have to be fixed. */
239 case PTRACE_POKETEXT
: /* write the word at location addr. */
240 case PTRACE_POKEDATA
:
242 if (access_process_vm(child
, addr
, &data
, sizeof(data
), 1) == sizeof(data
))
247 case PTRACE_POKEUSR
: /* write the word at location addr in the USER area */
249 if ((addr
& 3) || addr
< 0 ||
250 addr
> sizeof(struct user
) - 3)
253 if (addr
< 17*sizeof(long)) {
254 ret
= putreg(child
, addr
, data
);
258 /* We need to be very careful here. We implicitly
259 want to modify a portion of the task_struct, and we
260 have to be selective about what portions we allow someone
263 if(addr
>= (long) &dummy
->u_debugreg
[0] &&
264 addr
<= (long) &dummy
->u_debugreg
[7]){
266 if(addr
== (long) &dummy
->u_debugreg
[4]) return -EIO
;
267 if(addr
== (long) &dummy
->u_debugreg
[5]) return -EIO
;
268 if(addr
< (long) &dummy
->u_debugreg
[4] &&
269 ((unsigned long) data
) >= TASK_SIZE
-3) return -EIO
;
272 if(addr
== (long) &dummy
->u_debugreg
[7]) {
273 data
&= ~DR_CONTROL_RESERVED
;
275 if ((0x5f54 >> ((data
>> (16 + 4*i
)) & 0xf)) & 1)
279 addr
-= (long) &dummy
->u_debugreg
;
281 child
->thread
.debugreg
[addr
] = data
;
288 case PTRACE_SYSCALL
: /* continue and stop at next (return from) syscall */
289 case PTRACE_CONT
: { /* restart after signal. */
293 if ((unsigned long) data
> _NSIG
)
295 if (request
== PTRACE_SYSCALL
)
296 child
->flags
|= PF_TRACESYS
;
298 child
->flags
&= ~PF_TRACESYS
;
299 child
->exit_code
= data
;
300 /* make sure the single step bit is not set. */
301 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
302 put_stack_long(child
, EFL_OFFSET
,tmp
);
303 wake_up_process(child
);
309 * make the child exit. Best I can do is send it a sigkill.
310 * perhaps it should be put in the status that it wants to
317 if (child
->state
== TASK_ZOMBIE
) /* already dead */
319 child
->exit_code
= SIGKILL
;
320 /* make sure the single step bit is not set. */
321 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
322 put_stack_long(child
, EFL_OFFSET
, tmp
);
323 wake_up_process(child
);
327 case PTRACE_SINGLESTEP
: { /* set the trap flag. */
331 if ((unsigned long) data
> _NSIG
)
333 child
->flags
&= ~PF_TRACESYS
;
334 if ((child
->flags
& PF_DTRACE
) == 0) {
335 /* Spurious delayed TF traps may occur */
336 child
->flags
|= PF_DTRACE
;
338 tmp
= get_stack_long(child
, EFL_OFFSET
) | TRAP_FLAG
;
339 put_stack_long(child
, EFL_OFFSET
, tmp
);
340 child
->exit_code
= data
;
341 /* give it a chance to run. */
342 wake_up_process(child
);
347 case PTRACE_DETACH
: { /* detach a process that was attached. */
351 if ((unsigned long) data
> _NSIG
)
353 child
->flags
&= ~(PF_PTRACED
|PF_TRACESYS
);
354 child
->exit_code
= data
;
355 write_lock_irqsave(&tasklist_lock
, flags
);
357 child
->p_pptr
= child
->p_opptr
;
359 write_unlock_irqrestore(&tasklist_lock
, flags
);
360 /* make sure the single step bit is not set. */
361 tmp
= get_stack_long(child
, EFL_OFFSET
) & ~TRAP_FLAG
;
362 put_stack_long(child
, EFL_OFFSET
, tmp
);
363 wake_up_process(child
);
368 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
369 if (!access_ok(VERIFY_WRITE
, (unsigned *)data
,
375 for ( i
= 0; i
< 17*sizeof(long); i
+= sizeof(long) )
377 __put_user(getreg(child
, i
),(unsigned long *) data
);
378 data
+= sizeof(long);
384 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
386 if (!access_ok(VERIFY_READ
, (unsigned *)data
,
392 for ( i
= 0; i
< 17*sizeof(long); i
+= sizeof(long) )
394 __get_user(tmp
, (unsigned long *) data
);
395 putreg(child
, i
, tmp
);
396 data
+= sizeof(long);
402 case PTRACE_GETFPREGS
: { /* Get the child FPU state. */
403 if (!access_ok(VERIFY_WRITE
, (unsigned *)data
,
404 sizeof(struct user_i387_struct
)))
410 if ( !child
->used_math
) {
411 /* Simulate an empty FPU. */
412 child
->thread
.i387
.hard
.cwd
= 0xffff037f;
413 child
->thread
.i387
.hard
.swd
= 0xffff0000;
414 child
->thread
.i387
.hard
.twd
= 0xffffffff;
416 #ifdef CONFIG_MATH_EMULATION
417 if ( boot_cpu_data
.hard_math
) {
419 __copy_to_user((void *)data
, &child
->thread
.i387
.hard
,
420 sizeof(struct user_i387_struct
));
421 #ifdef CONFIG_MATH_EMULATION
423 save_i387_soft(&child
->thread
.i387
.soft
,
424 (struct _fpstate
*)data
);
430 case PTRACE_SETFPREGS
: { /* Set the child FPU state. */
431 if (!access_ok(VERIFY_READ
, (unsigned *)data
,
432 sizeof(struct user_i387_struct
)))
437 child
->used_math
= 1;
438 #ifdef CONFIG_MATH_EMULATION
439 if ( boot_cpu_data
.hard_math
) {
441 __copy_from_user(&child
->thread
.i387
.hard
, (void *)data
,
442 sizeof(struct user_i387_struct
));
443 #ifdef CONFIG_MATH_EMULATION
445 restore_i387_soft(&child
->thread
.i387
.soft
,
446 (struct _fpstate
*)data
);
462 asmlinkage
void syscall_trace(void)
464 if ((current
->flags
& (PF_PTRACED
|PF_TRACESYS
))
465 != (PF_PTRACED
|PF_TRACESYS
))
467 current
->exit_code
= SIGTRAP
;
468 current
->state
= TASK_STOPPED
;
469 notify_parent(current
, SIGCHLD
);
472 * this isn't the same as continuing with a signal, but it will do
473 * for normal use. strace only continues with a signal if the
474 * stopping signal is not SIGTRAP. -brl
476 if (current
->exit_code
) {
477 send_sig(current
->exit_code
, current
, 1);
478 current
->exit_code
= 0;