Import 2.3.12pre2
[davej-history.git] / kernel / ptrace.c
blob2b8fe0ddac1e7e19db9111bc5fe75d19910b4e7d
1 /*
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.
8 */
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/mm.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)
22 pgd_t * pgdir;
23 pmd_t * pgmiddle;
24 pte_t * pgtable;
25 unsigned long page;
27 repeat:
28 pgdir = pgd_offset(vma->vm_mm, addr);
29 if (pgd_none(*pgdir))
30 goto fault_in_page;
31 if (pgd_bad(*pgdir))
32 goto bad_pgd;
33 pgmiddle = pmd_offset(pgdir, addr);
34 if (pmd_none(*pgmiddle))
35 goto fault_in_page;
36 if (pmd_bad(*pgmiddle))
37 goto bad_pmd;
38 pgtable = pte_offset(pgmiddle, addr);
39 if (!pte_present(*pgtable))
40 goto fault_in_page;
41 page = pte_page(*pgtable);
42 if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
43 goto fault_in_page;
44 if (MAP_NR(page) >= max_mapnr)
45 return 0;
46 flush_cache_page(vma, addr);
48 void *src = (void *) (page + (addr & ~PAGE_MASK));
49 void *dst = buf;
51 if (write) {
52 dst = src;
53 src = buf;
55 memcpy(dst, src, len);
57 flush_page_to_ram(page);
58 return len;
60 fault_in_page:
61 /* -1: out of memory. 0 - unmapped page */
62 if (handle_mm_fault(tsk, vma, addr, write) > 0)
63 goto repeat;
64 return 0;
66 bad_pgd:
67 printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
68 return 0;
70 bad_pmd:
71 printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
72 return 0;
75 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
77 int copied;
78 struct vm_area_struct * vma = find_extend_vma(tsk, addr);
80 if (!vma)
81 return 0;
83 down(&tsk->mm->mmap_sem);
84 copied = 0;
85 for (;;) {
86 unsigned long offset = addr & ~PAGE_MASK;
87 int this_len = PAGE_SIZE - offset;
88 int retval;
90 if (this_len > len)
91 this_len = len;
92 retval = access_one_page(tsk, vma, addr, buf, this_len, write);
93 copied += retval;
94 if (retval != this_len)
95 break;
97 len -= retval;
98 if (!len)
99 break;
101 addr += retval;
102 buf += retval;
104 if (addr < vma->vm_end)
105 continue;
106 if (!vma->vm_next)
107 break;
108 if (vma->vm_next->vm_start != vma->vm_end)
109 break;
111 vma = vma->vm_next;
113 up(&tsk->mm->mmap_sem);
114 return copied;
117 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
119 int copied = 0;
121 while (len > 0) {
122 char buf[128];
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);
127 if (!retval) {
128 if (copied)
129 break;
130 return -EIO;
132 if (copy_to_user(dst, buf, retval))
133 return -EFAULT;
134 copied += retval;
135 src += retval;
136 dst += retval;
137 len -= retval;
139 return copied;
142 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
144 int copied = 0;
146 while (len > 0) {
147 char buf[128];
148 int this_len, retval;
150 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
151 if (copy_from_user(buf, src, this_len))
152 return -EFAULT;
153 retval = access_process_vm(tsk, dst, buf, this_len, 1);
154 if (!retval) {
155 if (copied)
156 break;
157 return -EIO;
159 copied += retval;
160 src += retval;
161 dst += retval;
162 len -= retval;
164 return copied;