1 /*
2 * linux/kernel/ptrace.c
3 *
4 * (C) Copyright 1999 Linus Torvalds
5 *
6 * Common interfaces for "ptrace()" which we do not want
7 * to continually duplicate across every architecture.
8 */
9
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/mm.h>
13 #include <linux/highmem.h>
14 #include <linux/smp_lock.h>
15
16 #include <asm/pgtable.h>
17 #include <asm/uaccess.h>
18
19 /*
20 * Access another process' address space, one page at a time.
21 */
22 static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
23 {
24 pgd_t * pgdir;
25 pmd_t * pgmiddle;
26 pte_t * pgtable;
27 char *maddr;
28 struct page *page;
29
30 repeat:
31 pgdir = pgd_offset(vma->vm_mm, addr);
32 if (pgd_none(*pgdir))
33 goto fault_in_page;
34 if (pgd_bad(*pgdir))
35 goto bad_pgd;
36 pgmiddle = pmd_offset(pgdir, addr);
37 if (pmd_none(*pgmiddle))
38 goto fault_in_page;
39 if (pmd_bad(*pgmiddle))
40 goto bad_pmd;
41 pgtable = pte_offset(pgmiddle, addr);
42 if (!pte_present(*pgtable))
43 goto fault_in_page;
44 if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
45 goto fault_in_page;
46 page = pte_page(*pgtable);
47
48 /* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */
49 if (page != ZERO_PAGE(addr) || write) {
50 if ((!VALID_PAGE(page)) || PageReserved(page))
51 return 0;
52 }
53 flush_cache_page(vma, addr);
54
55 if (write) {
56 maddr = kmap(page);
57 memcpy(maddr + (addr & ~PAGE_MASK), buf, len);
58 flush_page_to_ram(page);
59 flush_icache_page(vma, page);
60 kunmap(page);
61 } else {
62 maddr = kmap(page);
63 memcpy(buf, maddr + (addr & ~PAGE_MASK), len);
64 flush_page_to_ram(page);
65 kunmap(page);
66 }
67 return len;
68
69 fault_in_page:
70 /* -1: out of memory. 0 - unmapped page */
71 if (handle_mm_fault(mm, vma, addr, write) > 0)
72 goto repeat;
73 return 0;
74
75 bad_pgd:
76 pgd_ERROR(*pgdir);
77 return 0;
78
79 bad_pmd:
80 pmd_ERROR(*pgmiddle);
81 return 0;
82 }
83
84 static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
85 {
86 int copied = 0;
87
88 for (;;) {
89 unsigned long offset = addr & ~PAGE_MASK;
90 int this_len = PAGE_SIZE - offset;
91 int retval;
92
93 if (this_len > len)
94 this_len = len;
95 retval = access_one_page(mm, vma, addr, buf, this_len, write);
96 copied += retval;
97 if (retval != this_len)
98 break;
99
100 len -= retval;
101 if (!len)
102 break;
103
104 addr += retval;
105 buf += retval;
106
107 if (addr < vma->vm_end)
108 continue;
109 if (!vma->vm_next)
110 break;
111 if (vma->vm_next->vm_start != vma->vm_end)
112 break;
113
114 vma = vma->vm_next;
115 }
116 return copied;
117 }
118
119 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
120 {
121 int copied;
122 struct mm_struct *mm;
123 struct vm_area_struct * vma;
124
125 /* Worry about races with exit() */
126 task_lock(tsk);
127 mm = tsk->mm;
128 if (mm)
129 atomic_inc(&mm->mm_users);
130 task_unlock(tsk);
131 if (!mm)
132 return 0;
133
134 down(&mm->mmap_sem);
135 vma = find_extend_vma(mm, addr);
136 copied = 0;
137 if (vma)
138 copied = access_mm(mm, vma, addr, buf, len, write);
139
140 up(&mm->mmap_sem);
141 mmput(mm);
142 return copied;
143 }
144
145 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
146 {
147 int copied = 0;
148
149 while (len > 0) {
150 char buf[128];
151 int this_len, retval;
152
153 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
154 retval = access_process_vm(tsk, src, buf, this_len, 0);
155 if (!retval) {
156 if (copied)
157 break;
158 return -EIO;
159 }
160 if (copy_to_user(dst, buf, retval))
161 return -EFAULT;
162 copied += retval;
163 src += retval;
164 dst += retval;
165 len -= retval;
166 }
167 return copied;
168 }
169
170 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
171 {
172 int copied = 0;
173
174 while (len > 0) {
175 char buf[128];
176 int this_len, retval;
177
178 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
179 if (copy_from_user(buf, src, this_len))
180 return -EFAULT;
181 retval = access_process_vm(tsk, dst, buf, this_len, 1);
182 if (!retval) {
183 if (copied)
184 break;
185 return -EIO;
186 }
187 copied += retval;
188 src += retval;
189 dst += retval;
190 len -= retval;
191 }
192 return copied;
193 }
194
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.