2 * linux/kernel/ptrace.c
4 * (C) Copyright 1999 Linus Torvalds
6 * Common interfaces for "ptrace()" which we do not want
7 * to continually duplicate across every architecture.
10 #include <linux/sched.h>
11 #include <linux/errno.h>
14 #include <asm/pgtable.h>
15 #include <asm/uaccess.h>
18 * Access another process' address space, one page at a time.
20 static int access_one_page(struct task_struct
* tsk
, struct vm_area_struct
* vma
, unsigned long addr
, void *buf
, int len
, int write
)
28 pgdir
= pgd_offset(vma
->vm_mm
, addr
);
33 pgmiddle
= pmd_offset(pgdir
, addr
);
34 if (pmd_none(*pgmiddle
))
36 if (pmd_bad(*pgmiddle
))
38 pgtable
= pte_offset(pgmiddle
, addr
);
39 if (!pte_present(*pgtable
))
41 page
= pte_page(*pgtable
);
42 if (write
&& (!pte_write(*pgtable
) || !pte_dirty(*pgtable
)))
44 if (MAP_NR(page
) >= max_mapnr
)
46 flush_cache_page(vma
, addr
);
48 void *src
= (void *) (page
+ (addr
& ~PAGE_MASK
));
55 memcpy(dst
, src
, len
);
57 flush_page_to_ram(page
);
61 /* -1: out of memory. 0 - unmapped page */
62 if (handle_mm_fault(tsk
, vma
, addr
, write
) > 0)
67 printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk
->comm
, addr
, pgd_val(*pgdir
));
71 printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk
->comm
, addr
, pmd_val(*pgmiddle
));
75 int access_process_vm(struct task_struct
*tsk
, unsigned long addr
, void *buf
, int len
, int write
)
78 struct vm_area_struct
* vma
= find_extend_vma(tsk
, addr
);
83 down(&tsk
->mm
->mmap_sem
);
86 unsigned long offset
= addr
& ~PAGE_MASK
;
87 int this_len
= PAGE_SIZE
- offset
;
92 retval
= access_one_page(tsk
, vma
, addr
, buf
, this_len
, write
);
94 if (retval
!= this_len
)
104 if (addr
< vma
->vm_end
)
108 if (vma
->vm_next
->vm_start
!= vma
->vm_end
)
113 up(&tsk
->mm
->mmap_sem
);
117 int ptrace_readdata(struct task_struct
*tsk
, unsigned long src
, char *dst
, int len
)
123 int this_len
, retval
;
125 this_len
= (len
> sizeof(buf
)) ? sizeof(buf
) : len
;
126 retval
= access_process_vm(tsk
, src
, buf
, this_len
, 0);
132 if (copy_to_user(dst
, buf
, retval
))
142 int ptrace_writedata(struct task_struct
*tsk
, char * src
, unsigned long dst
, int len
)
148 int this_len
, retval
;
150 this_len
= (len
> sizeof(buf
)) ? sizeof(buf
) : len
;
151 if (copy_from_user(buf
, src
, this_len
))
153 retval
= access_process_vm(tsk
, dst
, buf
, this_len
, 1);