pre-2.3.4..
[davej-history.git] / arch / ppc / kernel / ptrace.c
blobb101a3e9696822ca02a0a3334c1aecd2169bc943
1 /*
2 * linux/arch/ppc/kernel/ptrace.c
4 * PowerPC version
5 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
7 * Derived from "arch/m68k/kernel/ptrace.c"
8 * Copyright (C) 1994 by Hamish Macdonald
9 * Taken from linux/kernel/ptrace.c and modified for M680x0.
10 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
12 * Modified by Cort Dougan (cort@cs.nmt.edu)
14 * This file is subject to the terms and conditions of the GNU General
15 * Public License. See the file README.legal in the main directory of
16 * this archive for more details.
19 #include <stddef.h>
20 #include <linux/kernel.h>
21 #include <linux/sched.h>
22 #include <linux/mm.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25 #include <linux/errno.h>
26 #include <linux/ptrace.h>
27 #include <linux/user.h>
29 #include <asm/segment.h>
30 #include <asm/page.h>
31 #include <asm/pgtable.h>
32 #include <asm/system.h>
35 * Set of msr bits that gdb can change on behalf of a process.
37 #define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
40 * does not yet catch signals sent when the child dies.
41 * in exit.c or in signal.c.
45 * Get contents of register REGNO in task TASK.
47 static inline long get_reg(struct task_struct *task, int regno)
49 if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
50 return ((unsigned long *)task->tss.regs)[regno];
51 return (0);
55 * Write contents of register REGNO in task TASK.
57 static inline int put_reg(struct task_struct *task, int regno,
58 unsigned long data)
60 if (regno <= PT_MQ) {
61 if (regno == PT_MSR)
62 data = (data & MSR_DEBUGCHANGE)
63 | (task->tss.regs->msr & ~MSR_DEBUGCHANGE);
64 ((unsigned long *)task->tss.regs)[regno] = data;
65 return 0;
67 return -1;
70 static inline void
71 set_single_step(struct task_struct *task)
73 struct pt_regs *regs = task->tss.regs;
74 regs->msr |= MSR_SE;
77 static inline void
78 clear_single_step(struct task_struct *task)
80 struct pt_regs *regs = task->tss.regs;
81 regs->msr &= ~MSR_SE;
85 * This routine gets a long from any process space by following the page
86 * tables. NOTE! You should check that the long isn't on a page boundary,
87 * and that it is in the task area before calling this: this routine does
88 * no checking.
91 static unsigned long get_long(struct task_struct * tsk,
92 struct vm_area_struct * vma, unsigned long addr)
94 pgd_t * pgdir;
95 pmd_t * pgmiddle;
96 pte_t * pgtable;
97 unsigned long page;
99 repeat:
100 pgdir = pgd_offset(vma->vm_mm, addr);
101 if (pgd_none(*pgdir)) {
102 handle_mm_fault(tsk, vma, addr, 0);
103 goto repeat;
105 if (pgd_bad(*pgdir)) {
106 printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
107 pgd_clear(pgdir);
108 return 0;
110 pgmiddle = pmd_offset(pgdir,addr);
111 if (pmd_none(*pgmiddle)) {
112 handle_mm_fault(tsk, vma, addr, 0);
113 goto repeat;
115 if (pmd_bad(*pgmiddle)) {
116 printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
117 pmd_clear(pgmiddle);
118 return 0;
120 pgtable = pte_offset(pgmiddle, addr);
121 if (!pte_present(*pgtable)) {
122 handle_mm_fault(tsk, vma, addr, 0);
123 goto repeat;
125 page = pte_page(*pgtable);
126 /* this is a hack for non-kernel-mapped video buffers and similar */
127 if (MAP_NR(page) >= max_mapnr)
128 return 0;
129 page += addr & ~PAGE_MASK;
130 return *(unsigned long *) page;
134 * This routine puts a long into any process space by following the page
135 * tables. NOTE! You should check that the long isn't on a page boundary,
136 * and that it is in the task area before calling this: this routine does
137 * no checking.
139 * Now keeps R/W state of page so that a text page stays readonly
140 * even if a debugger scribbles breakpoints into it. -M.U-
142 static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
143 unsigned long addr, unsigned long data)
145 pgd_t *pgdir;
146 pmd_t *pgmiddle;
147 pte_t *pgtable;
148 unsigned long page;
150 repeat:
151 pgdir = pgd_offset(vma->vm_mm, addr);
152 if (!pgd_present(*pgdir)) {
153 handle_mm_fault(tsk, vma, addr, 1);
154 goto repeat;
156 if (pgd_bad(*pgdir)) {
157 printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
158 pgd_clear(pgdir);
159 return;
161 pgmiddle = pmd_offset(pgdir,addr);
162 if (pmd_none(*pgmiddle)) {
163 handle_mm_fault(tsk, vma, addr, 1);
164 goto repeat;
166 if (pmd_bad(*pgmiddle)) {
167 printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
168 pmd_clear(pgmiddle);
169 return;
171 pgtable = pte_offset(pgmiddle, addr);
172 if (!pte_present(*pgtable)) {
173 handle_mm_fault(tsk, vma, addr, 1);
174 goto repeat;
176 page = pte_page(*pgtable);
177 if (!pte_write(*pgtable)) {
178 handle_mm_fault(tsk, vma, addr, 1);
179 goto repeat;
181 /* this is a hack for non-kernel-mapped video buffers and similar */
182 if (MAP_NR(page) < max_mapnr) {
183 unsigned long phys_addr = page + (addr & ~PAGE_MASK);
184 *(unsigned long *) phys_addr = data;
185 flush_icache_range(phys_addr, phys_addr+4);
187 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
188 /* this should also re-instate whatever read-only mode there was before */
189 set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
190 flush_tlb_all();
193 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
195 struct vm_area_struct * vma;
197 addr &= PAGE_MASK;
198 vma = find_vma(tsk->mm,addr);
199 if (!vma)
200 return NULL;
201 if (vma->vm_start <= addr)
202 return vma;
203 if (!(vma->vm_flags & VM_GROWSDOWN))
204 return NULL;
205 if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
206 return NULL;
207 vma->vm_offset -= vma->vm_start - addr;
208 vma->vm_start = addr;
209 return vma;
213 * This routine checks the page boundaries, and that the offset is
214 * within the task area. It then calls get_long() to read a long.
216 static int read_long(struct task_struct * tsk, unsigned long addr,
217 unsigned long * result)
219 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
221 if (!vma)
222 return -EIO;
223 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
224 unsigned long low,high;
225 struct vm_area_struct * vma_low = vma;
227 if (addr + sizeof(long) >= vma->vm_end) {
228 vma_low = vma->vm_next;
229 if (!vma_low || vma_low->vm_start != vma->vm_end)
230 return -EIO;
232 high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
233 low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
234 switch (addr & (sizeof(long)-1)) {
235 case 3:
236 low >>= 8;
237 low |= high << 24;
238 break;
239 case 2:
240 low >>= 16;
241 low |= high << 16;
242 break;
243 case 1:
244 low >>= 24;
245 low |= high << 8;
246 break;
248 *result = low;
249 } else
250 *result = get_long(tsk, vma,addr);
251 return 0;
255 * This routine checks the page boundaries, and that the offset is
256 * within the task area. It then calls put_long() to write a long.
258 static int write_long(struct task_struct * tsk, unsigned long addr,
259 unsigned long data)
261 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
263 if (!vma)
264 return -EIO;
265 if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
266 unsigned long low,high;
267 struct vm_area_struct * vma_low = vma;
269 if (addr + sizeof(long) >= vma->vm_end) {
270 vma_low = vma->vm_next;
271 if (!vma_low || vma_low->vm_start != vma->vm_end)
272 return -EIO;
274 high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
275 low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
276 switch (addr & (sizeof(long)-1)) {
277 case 0: /* shouldn't happen, but safety first */
278 high = data;
279 break;
280 case 3:
281 low &= 0x000000ff;
282 low |= data << 8;
283 high &= ~0xff;
284 high |= data >> 24;
285 break;
286 case 2:
287 low &= 0x0000ffff;
288 low |= data << 16;
289 high &= ~0xffff;
290 high |= data >> 16;
291 break;
292 case 1:
293 low &= 0x00ffffff;
294 low |= data << 24;
295 high &= ~0xffffff;
296 high |= data >> 8;
297 break;
299 put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
300 put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
301 } else
302 put_long(tsk, vma,addr,data);
303 return 0;
306 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
308 struct task_struct *child;
309 int ret = -EPERM;
311 lock_kernel();
312 if (request == PTRACE_TRACEME) {
313 /* are we already being traced? */
314 if (current->flags & PF_PTRACED)
315 goto out;
316 /* set the ptrace bit in the process flags. */
317 current->flags |= PF_PTRACED;
318 ret = 0;
319 goto out;
321 if (pid == 1) /* you may not mess with init */
322 goto out;
323 ret = -ESRCH;
324 if (!(child = find_task_by_pid(pid)))
325 goto out;
326 ret = -EPERM;
327 if (request == PTRACE_ATTACH) {
328 if (child == current)
329 goto out;
330 if ((!child->dumpable ||
331 (current->uid != child->euid) ||
332 (current->uid != child->uid) ||
333 (current->uid != child->suid) ||
334 (current->gid != child->egid) ||
335 (current->gid != child->gid) ||
336 (current->gid != child->sgid) ||
337 (!cap_issubset(child->cap_permitted, current->cap_permitted)))
338 && !capable(CAP_SYS_PTRACE))
339 goto out;
340 /* the same process cannot be attached many times */
341 if (child->flags & PF_PTRACED)
342 goto out;
343 child->flags |= PF_PTRACED;
344 if (child->p_pptr != current) {
345 REMOVE_LINKS(child);
346 child->p_pptr = current;
347 SET_LINKS(child);
349 send_sig(SIGSTOP, child, 1);
350 ret = 0;
351 goto out;
353 ret = -ESRCH;
354 if (!(child->flags & PF_PTRACED))
355 goto out;
356 if (child->state != TASK_STOPPED) {
357 if (request != PTRACE_KILL)
358 goto out;
360 if (child->p_pptr != current)
361 goto out;
363 switch (request) {
364 /* If I and D space are separate, these will need to be fixed. */
365 case PTRACE_PEEKTEXT: /* read word at location addr. */
366 case PTRACE_PEEKDATA: {
367 unsigned long tmp;
369 down(&child->mm->mmap_sem);
370 ret = read_long(child, addr, &tmp);
371 up(&child->mm->mmap_sem);
372 if (ret < 0)
373 goto out;
374 ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
375 if (!ret)
376 put_user(tmp, (unsigned long *) data);
377 goto out;
380 /* read the word at location addr in the USER area. */
381 case PTRACE_PEEKUSR: {
382 unsigned long tmp;
384 if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
385 ret = -EIO;
386 goto out;
389 ret = verify_area(VERIFY_WRITE, (void *) data,
390 sizeof(long));
391 if (ret)
392 goto out;
393 tmp = 0; /* Default return condition */
394 addr = addr >> 2; /* temporary hack. */
395 if (addr < PT_FPR0) {
396 tmp = get_reg(child, addr);
398 else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
399 if (child->tss.regs->msr & MSR_FP)
400 giveup_fpu(child);
401 tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
403 else
404 ret = -EIO;
405 if (!ret)
406 put_user(tmp,(unsigned long *) data);
407 goto out;
410 /* If I and D space are separate, this will have to be fixed. */
411 case PTRACE_POKETEXT: /* write the word at location addr. */
412 case PTRACE_POKEDATA:
413 down(&child->mm->mmap_sem);
414 ret = write_long(child,addr,data);
415 up(&child->mm->mmap_sem);
416 goto out;
418 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
419 ret = -EIO;
420 if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
421 goto out;
423 addr = addr >> 2; /* temporary hack. */
425 if (addr == PT_ORIG_R3)
426 goto out;
427 if (addr < PT_FPR0) {
428 if (put_reg(child, addr, data))
429 goto out;
430 ret = 0;
431 goto out;
433 if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
434 if (child->tss.regs->msr & MSR_FP)
435 giveup_fpu(child);
436 ((long *)child->tss.fpr)[addr - PT_FPR0] = data;
437 ret = 0;
438 goto out;
440 goto out;
442 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
443 case PTRACE_CONT: { /* restart after signal. */
444 ret = -EIO;
445 if ((unsigned long) data >= _NSIG)
446 goto out;
447 if (request == PTRACE_SYSCALL)
448 child->flags |= PF_TRACESYS;
449 else
450 child->flags &= ~PF_TRACESYS;
451 child->exit_code = data;
452 wake_up_process(child);
453 /* make sure the single step bit is not set. */
454 clear_single_step(child);
455 ret = 0;
456 goto out;
460 * make the child exit. Best I can do is send it a sigkill.
461 * perhaps it should be put in the status that it wants to
462 * exit.
464 case PTRACE_KILL: {
465 ret = 0;
466 if (child->state == TASK_ZOMBIE) /* already dead */
467 goto out;
468 wake_up_process(child);
469 child->exit_code = SIGKILL;
470 /* make sure the single step bit is not set. */
471 clear_single_step(child);
472 goto out;
475 case PTRACE_SINGLESTEP: { /* set the trap flag. */
476 ret = -EIO;
477 if ((unsigned long) data >= _NSIG)
478 goto out;
479 child->flags &= ~PF_TRACESYS;
480 set_single_step(child);
481 wake_up_process(child);
482 child->exit_code = data;
483 /* give it a chance to run. */
484 ret = 0;
485 goto out;
488 case PTRACE_DETACH: { /* detach a process that was attached. */
489 ret = -EIO;
490 if ((unsigned long) data >= _NSIG)
491 goto out;
492 child->flags &= ~(PF_PTRACED|PF_TRACESYS);
493 wake_up_process(child);
494 child->exit_code = data;
495 REMOVE_LINKS(child);
496 child->p_pptr = child->p_opptr;
497 SET_LINKS(child);
498 /* make sure the single step bit is not set. */
499 clear_single_step(child);
500 ret = 0;
501 goto out;
504 default:
505 ret = -EIO;
506 goto out;
508 out:
509 unlock_kernel();
510 return ret;
513 asmlinkage void syscall_trace(void)
515 lock_kernel();
516 if ((current->flags & (PF_PTRACED|PF_TRACESYS))
517 != (PF_PTRACED|PF_TRACESYS))
518 goto out;
519 current->exit_code = SIGTRAP;
520 current->state = TASK_STOPPED;
521 notify_parent(current, SIGCHLD);
522 schedule();
524 * this isn't the same as continuing with a signal, but it will do
525 * for normal use. strace only continues with a signal if the
526 * stopping signal is not SIGTRAP. -brl
528 if (current->exit_code) {
529 send_sig(current->exit_code, current, 1);
530 current->exit_code = 0;
532 out:
533 unlock_kernel();