2 * linux/arch/m68k/kernel/ptrace.c
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
16 #include <linux/smp.h>
17 #include <linux/smp_lock.h>
18 #include <linux/errno.h>
19 #include <linux/ptrace.h>
20 #include <linux/user.h>
21 #include <linux/config.h>
23 #include <asm/uaccess.h>
25 #include <asm/pgtable.h>
26 #include <asm/system.h>
27 #include <asm/processor.h>
30 * does not yet catch signals sent when the child dies.
31 * in exit.c or in signal.c.
34 /* determines which bits in the SR the user has access to. */
35 /* 1 = access 0 = no access */
36 #define SR_MASK 0x001f
38 /* sets the trace bits. */
39 #define TRACE_BITS 0x8000
41 /* Find the stack offset for a register, relative to thread.esp0. */
42 #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
43 #define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
44 - sizeof(struct switch_stack))
45 /* Mapping from PT_xxx to the stack offset at which the register is
46 saved. Notice that usp has no stack-slot and needs to be treated
47 specially (see get_reg/put_reg below). */
48 static int regoff
[] = {
49 PT_REG(d1
), PT_REG(d2
), PT_REG(d3
), PT_REG(d4
),
50 PT_REG(d5
), SW_REG(d6
), SW_REG(d7
), PT_REG(a0
),
51 PT_REG(a1
), PT_REG(a2
), SW_REG(a3
), SW_REG(a4
),
52 SW_REG(a5
), SW_REG(a6
), PT_REG(d0
), -1,
53 PT_REG(orig_d0
), PT_REG(sr
), PT_REG(pc
),
57 * Get contents of register REGNO in task TASK.
59 static inline long get_reg(struct task_struct
*task
, int regno
)
64 addr
= &task
->thread
.usp
;
65 else if (regno
< sizeof(regoff
)/sizeof(regoff
[0]))
66 addr
= (unsigned long *)(task
->thread
.esp0
+ regoff
[regno
]);
73 * Write contents of register REGNO in task TASK.
75 static inline int put_reg(struct task_struct
*task
, int regno
,
81 addr
= &task
->thread
.usp
;
82 else if (regno
< sizeof(regoff
)/sizeof(regoff
[0]))
83 addr
= (unsigned long *) (task
->thread
.esp0
+ regoff
[regno
]);
91 * This routine gets a long from any process space by following the page
92 * tables. NOTE! You should check that the long isn't on a page boundary,
93 * and that it is in the task area before calling this: this routine does
97 static unsigned long get_long(struct task_struct
* tsk
,
98 struct vm_area_struct
* vma
, unsigned long addr
)
106 pgdir
= pgd_offset(vma
->vm_mm
, addr
);
107 if (pgd_none(*pgdir
)) {
108 handle_mm_fault(tsk
, vma
, addr
, 0);
111 if (pgd_bad(*pgdir
)) {
112 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir
));
116 pgmiddle
= pmd_offset(pgdir
,addr
);
117 if (pmd_none(*pgmiddle
)) {
118 handle_mm_fault(tsk
, vma
, addr
, 0);
121 if (pmd_bad(*pgmiddle
)) {
122 printk("ptrace: bad page directory %08lx\n",
127 pgtable
= pte_offset(pgmiddle
, addr
);
128 if (!pte_present(*pgtable
)) {
129 handle_mm_fault(tsk
, vma
, addr
, 0);
132 page
= pte_page(*pgtable
);
133 /* this is a hack for non-kernel-mapped video buffers and similar */
134 if (MAP_NR(page
) >= max_mapnr
)
136 page
+= addr
& ~PAGE_MASK
;
137 return *(unsigned long *) page
;
141 * This routine puts a long into any process space by following the page
142 * tables. NOTE! You should check that the long isn't on a page boundary,
143 * and that it is in the task area before calling this: this routine does
146 * Now keeps R/W state of page so that a text page stays readonly
147 * even if a debugger scribbles breakpoints into it. -M.U-
149 static void put_long(struct task_struct
* tsk
, struct vm_area_struct
* vma
, unsigned long addr
,
158 pgdir
= pgd_offset(vma
->vm_mm
, addr
);
159 if (!pgd_present(*pgdir
)) {
160 handle_mm_fault(tsk
, vma
, addr
, 1);
163 if (pgd_bad(*pgdir
)) {
164 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir
));
168 pgmiddle
= pmd_offset(pgdir
,addr
);
169 if (pmd_none(*pgmiddle
)) {
170 handle_mm_fault(tsk
, vma
, addr
, 1);
173 if (pmd_bad(*pgmiddle
)) {
174 printk("ptrace: bad page directory %08lx\n",
179 pgtable
= pte_offset(pgmiddle
, addr
);
180 if (!pte_present(*pgtable
)) {
181 handle_mm_fault(tsk
, vma
, addr
, 1);
184 page
= pte_page(*pgtable
);
185 if (!pte_write(*pgtable
)) {
186 handle_mm_fault(tsk
, vma
, addr
, 1);
189 /* this is a hack for non-kernel-mapped video buffers and similar */
190 if (MAP_NR(page
) < max_mapnr
) {
191 *(unsigned long *) (page
+ (addr
& ~PAGE_MASK
)) = data
;
192 flush_page_to_ram (page
);
194 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
195 /* this should also re-instate whatever read-only mode there was before */
196 *pgtable
= pte_mkdirty(mk_pte(page
, vma
->vm_page_prot
));
201 * This routine checks the page boundaries, and that the offset is
202 * within the task area. It then calls get_long() to read a long.
204 static int read_long(struct task_struct
* tsk
, unsigned long addr
,
205 unsigned long * result
)
207 struct vm_area_struct
* vma
= find_extend_vma(tsk
, addr
);
211 if ((addr
& ~PAGE_MASK
) > PAGE_SIZE
-sizeof(long)) {
212 unsigned long low
,high
;
213 struct vm_area_struct
* vma_low
= vma
;
215 if (addr
+ sizeof(long) >= vma
->vm_end
) {
216 vma_low
= vma
->vm_next
;
217 if (!vma_low
|| vma_low
->vm_start
!= vma
->vm_end
)
220 high
= get_long(tsk
, vma
,addr
& ~(sizeof(long)-1));
221 low
= get_long(tsk
, vma_low
,(addr
+sizeof(long)) & ~(sizeof(long)-1));
222 switch (addr
& (sizeof(long)-1)) {
238 *result
= get_long(tsk
, vma
,addr
);
243 * This routine checks the page boundaries, and that the offset is
244 * within the task area. It then calls put_long() to write a long.
246 static int write_long(struct task_struct
* tsk
, unsigned long addr
,
249 struct vm_area_struct
* vma
= find_extend_vma(tsk
, addr
);
253 if ((addr
& ~PAGE_MASK
) > PAGE_SIZE
-sizeof(long)) {
254 unsigned long low
,high
;
255 struct vm_area_struct
* vma_low
= vma
;
257 if (addr
+ sizeof(long) >= vma
->vm_end
) {
258 vma_low
= vma
->vm_next
;
259 if (!vma_low
|| vma_low
->vm_start
!= vma
->vm_end
)
262 high
= get_long(tsk
, vma
,addr
& ~(sizeof(long)-1));
263 low
= get_long(tsk
, vma_low
,(addr
+sizeof(long)) & ~(sizeof(long)-1));
264 switch (addr
& (sizeof(long)-1)) {
265 case 0: /* shouldn't happen, but safety first */
287 put_long(tsk
, vma
,addr
& ~(sizeof(long)-1),high
);
288 put_long(tsk
, vma_low
,(addr
+sizeof(long)) & ~(sizeof(long)-1),low
);
290 put_long(tsk
, vma
,addr
,data
);
294 asmlinkage
int sys_ptrace(long request
, long pid
, long addr
, long data
)
296 struct task_struct
*child
;
302 if (request
== PTRACE_TRACEME
) {
303 /* are we already being traced? */
304 if (current
->flags
& PF_PTRACED
)
306 /* set the ptrace bit in the process flags. */
307 current
->flags
|= PF_PTRACED
;
312 read_lock(&tasklist_lock
);
313 child
= find_task_by_pid(pid
);
314 read_unlock(&tasklist_lock
); /* FIXME!!! */
318 if (pid
== 1) /* you may not mess with init */
320 if (request
== PTRACE_ATTACH
) {
321 if (child
== current
)
323 if ((!child
->dumpable
||
324 (current
->uid
!= child
->euid
) ||
325 (current
->uid
!= child
->suid
) ||
326 (current
->uid
!= child
->uid
) ||
327 (current
->gid
!= child
->egid
) ||
328 (current
->gid
!= child
->sgid
) ||
329 (!cap_issubset(child
->cap_permitted
, current
->cap_permitted
)) ||
330 (current
->gid
!= child
->gid
)) && !capable(CAP_SYS_PTRACE
))
332 /* the same process cannot be attached many times */
333 if (child
->flags
& PF_PTRACED
)
335 child
->flags
|= PF_PTRACED
;
337 write_lock_irqsave(&tasklist_lock
, flags
);
338 if (child
->p_pptr
!= current
) {
340 child
->p_pptr
= current
;
343 write_unlock_irqrestore(&tasklist_lock
, flags
);
345 send_sig(SIGSTOP
, child
, 1);
350 if (!(child
->flags
& PF_PTRACED
))
352 if (child
->state
!= TASK_STOPPED
) {
353 if (request
!= PTRACE_KILL
)
356 if (child
->p_pptr
!= current
)
360 /* when I and D space are separate, these will need to be fixed. */
361 case PTRACE_PEEKTEXT
: /* read word at location addr. */
362 case PTRACE_PEEKDATA
: {
365 down(&child
->mm
->mmap_sem
);
366 ret
= read_long(child
, addr
, &tmp
);
367 up(&child
->mm
->mmap_sem
);
369 ret
= put_user(tmp
, (unsigned long *) data
);
373 /* read the word at location addr in the USER area. */
374 case PTRACE_PEEKUSR
: {
378 if ((addr
& 3) || addr
< 0 || addr
>= sizeof(struct user
))
381 tmp
= 0; /* Default return condition */
382 addr
= addr
>> 2; /* temporary hack. */
385 tmp
= get_reg(child
, addr
);
388 } else if (addr
>= 21 && addr
< 49) {
389 tmp
= child
->thread
.fp
[addr
- 21];
390 #ifdef CONFIG_M68KFPU_EMU
391 /* Convert internal fpu reg representation
392 * into long double format
394 if (FPU_IS_EMU
&& (addr
< 45) && !(addr
% 3))
395 tmp
= ((tmp
& 0xffff0000) << 15) |
396 ((tmp
& 0x0000ffff) << 16);
400 ret
= put_user(tmp
,(unsigned long *) data
);
404 /* when I and D space are separate, this will have to be fixed. */
405 case PTRACE_POKETEXT
: /* write the word at location addr. */
406 case PTRACE_POKEDATA
:
407 down(&child
->mm
->mmap_sem
);
408 ret
= write_long(child
,addr
,data
);
409 up(&child
->mm
->mmap_sem
);
412 case PTRACE_POKEUSR
: /* write the word at location addr in the USER area */
414 if ((addr
& 3) || addr
< 0 || addr
>= sizeof(struct user
))
417 addr
= addr
>> 2; /* temporary hack. */
419 if (addr
== PT_ORIG_D0
)
424 data
|= get_reg(child
, PT_SR
) & ~(SR_MASK
<< 16);
427 if (put_reg(child
, addr
, data
))
432 if (addr
>= 21 && addr
< 48)
434 #ifdef CONFIG_M68KFPU_EMU
435 /* Convert long double format
436 * into internal fpu reg representation
438 if (FPU_IS_EMU
&& (addr
< 45) && !(addr
% 3)) {
439 data
= (unsigned long)data
<< 15;
440 data
= (data
& 0xffff0000) |
441 ((data
& 0x0000ffff) >> 1);
444 child
->thread
.fp
[addr
- 21] = data
;
449 case PTRACE_SYSCALL
: /* continue and stop at next (return from) syscall */
450 case PTRACE_CONT
: { /* restart after signal. */
454 if ((unsigned long) data
> _NSIG
)
456 if (request
== PTRACE_SYSCALL
)
457 child
->flags
|= PF_TRACESYS
;
459 child
->flags
&= ~PF_TRACESYS
;
460 child
->exit_code
= data
;
461 /* make sure the single step bit is not set. */
462 tmp
= get_reg(child
, PT_SR
) & ~(TRACE_BITS
<< 16);
463 put_reg(child
, PT_SR
, tmp
);
464 wake_up_process(child
);
470 * make the child exit. Best I can do is send it a sigkill.
471 * perhaps it should be put in the status that it wants to
478 if (child
->state
== TASK_ZOMBIE
) /* already dead */
480 child
->exit_code
= SIGKILL
;
481 /* make sure the single step bit is not set. */
482 tmp
= get_reg(child
, PT_SR
) & ~(TRACE_BITS
<< 16);
483 put_reg(child
, PT_SR
, tmp
);
484 wake_up_process(child
);
488 case PTRACE_SINGLESTEP
: { /* set the trap flag. */
492 if ((unsigned long) data
> _NSIG
)
494 child
->flags
&= ~PF_TRACESYS
;
495 tmp
= get_reg(child
, PT_SR
) | (TRACE_BITS
<< 16);
496 put_reg(child
, PT_SR
, tmp
);
498 child
->exit_code
= data
;
499 /* give it a chance to run. */
500 wake_up_process(child
);
505 case PTRACE_DETACH
: { /* detach a process that was attached. */
509 if ((unsigned long) data
> _NSIG
)
511 child
->flags
&= ~(PF_PTRACED
|PF_TRACESYS
);
512 child
->exit_code
= data
;
513 write_lock_irqsave(&tasklist_lock
, flags
);
515 child
->p_pptr
= child
->p_opptr
;
517 write_unlock_irqrestore(&tasklist_lock
, flags
);
518 /* make sure the single step bit is not set. */
519 tmp
= get_reg(child
, PT_SR
) & ~(TRACE_BITS
<< 16);
520 put_reg(child
, PT_SR
, tmp
);
521 wake_up_process(child
);
526 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
529 for (i
= 0; i
< 19; i
++) {
530 tmp
= get_reg(child
, i
);
533 if (put_user(tmp
, (unsigned long *) data
)) {
537 data
+= sizeof(long);
543 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
546 for (i
= 0; i
< 19; i
++) {
547 if (get_user(tmp
, (unsigned long *) data
)) {
554 tmp
|= get_reg(child
, PT_SR
) & ~(SR_MASK
<< 16);
556 put_reg(child
, i
, tmp
);
557 data
+= sizeof(long);
563 case PTRACE_GETFPREGS
: { /* Get the child FPU state. */
565 if (copy_to_user((void *)data
, &child
->thread
.fp
,
566 sizeof(struct user_m68kfp_struct
)))
571 case PTRACE_SETFPREGS
: { /* Set the child FPU state. */
573 if (copy_from_user(&child
->thread
.fp
, (void *)data
,
574 sizeof(struct user_m68kfp_struct
)))
588 asmlinkage
void syscall_trace(void)
591 if ((current
->flags
& (PF_PTRACED
|PF_TRACESYS
))
592 != (PF_PTRACED
|PF_TRACESYS
))
594 current
->exit_code
= SIGTRAP
;
595 current
->state
= TASK_STOPPED
;
596 notify_parent(current
, SIGCHLD
);
599 * this isn't the same as continuing with a signal, but it will do
600 * for normal use. strace only continues with a signal if the
601 * stopping signal is not SIGTRAP. -brl
603 if (current
->exit_code
) {
604 send_sig(current
->exit_code
, current
, 1);
605 current
->exit_code
= 0;