Make HZ_TO_STD macro name lowercase.
[linux-2.6/linux-mips.git] / kernel / ptrace.c
blobe009bca35e45f26fc431c58e7fdfb06007ce471c
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>
13 #include <linux/highmem.h>
14 #include <linux/smp_lock.h>
16 #include <asm/pgtable.h>
17 #include <asm/uaccess.h>
20 * Access another process' address space, one page at a time.
22 static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
24 pgd_t * pgdir;
25 pmd_t * pgmiddle;
26 pte_t * pgtable;
27 unsigned long mapnr;
28 unsigned long maddr;
29 struct page *page;
31 repeat:
32 pgdir = pgd_offset(vma->vm_mm, addr);
33 if (pgd_none(*pgdir))
34 goto fault_in_page;
35 if (pgd_bad(*pgdir))
36 goto bad_pgd;
37 pgmiddle = pmd_offset(pgdir, addr);
38 if (pmd_none(*pgmiddle))
39 goto fault_in_page;
40 if (pmd_bad(*pgmiddle))
41 goto bad_pmd;
42 pgtable = pte_offset(pgmiddle, addr);
43 if (!pte_present(*pgtable))
44 goto fault_in_page;
45 mapnr = pte_pagenr(*pgtable);
46 if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
47 goto fault_in_page;
48 page = mem_map + mapnr;
49 if ((mapnr >= max_mapnr) || PageReserved(page))
50 return 0;
51 flush_cache_page(vma, addr);
53 if (write) {
54 maddr = kmap(page);
55 memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
56 flush_page_to_ram(page);
57 flush_icache_page(vma, page);
58 kunmap(page);
59 } else {
60 maddr = kmap(page);
61 memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len);
62 flush_page_to_ram(page);
63 kunmap(page);
65 return len;
67 fault_in_page:
68 /* -1: out of memory. 0 - unmapped page */
69 if (handle_mm_fault(mm, vma, addr, write) > 0)
70 goto repeat;
71 return 0;
73 bad_pgd:
74 pgd_ERROR(*pgdir);
75 return 0;
77 bad_pmd:
78 pmd_ERROR(*pgmiddle);
79 return 0;
82 static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
84 int copied = 0;
86 for (;;) {
87 unsigned long offset = addr & ~PAGE_MASK;
88 int this_len = PAGE_SIZE - offset;
89 int retval;
91 if (this_len > len)
92 this_len = len;
93 retval = access_one_page(mm, vma, addr, buf, this_len, write);
94 copied += retval;
95 if (retval != this_len)
96 break;
98 len -= retval;
99 if (!len)
100 break;
102 addr += retval;
103 buf += retval;
105 if (addr < vma->vm_end)
106 continue;
107 if (!vma->vm_next)
108 break;
109 if (vma->vm_next->vm_start != vma->vm_end)
110 break;
112 vma = vma->vm_next;
114 return copied;
117 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
119 int copied;
120 struct mm_struct *mm;
121 struct vm_area_struct * vma;
123 /* Worry about races with exit() */
124 task_lock(tsk);
125 mm = tsk->mm;
126 if (mm)
127 atomic_inc(&mm->mm_users);
128 task_unlock(tsk);
129 if (!mm)
130 return 0;
132 down(&mm->mmap_sem);
133 vma = find_extend_vma(mm, addr);
134 copied = 0;
135 if (vma)
136 copied = access_mm(mm, vma, addr, buf, len, write);
138 up(&mm->mmap_sem);
139 mmput(mm);
140 return copied;
143 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
145 int copied = 0;
147 while (len > 0) {
148 char buf[128];
149 int this_len, retval;
151 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
152 retval = access_process_vm(tsk, src, buf, this_len, 0);
153 if (!retval) {
154 if (copied)
155 break;
156 return -EIO;
158 if (copy_to_user(dst, buf, retval))
159 return -EFAULT;
160 copied += retval;
161 src += retval;
162 dst += retval;
163 len -= retval;
165 return copied;
168 int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
170 int copied = 0;
172 while (len > 0) {
173 char buf[128];
174 int this_len, retval;
176 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
177 if (copy_from_user(buf, src, this_len))
178 return -EFAULT;
179 retval = access_process_vm(tsk, dst, buf, this_len, 1);
180 if (!retval) {
181 if (copied)
182 break;
183 return -EIO;
185 copied += retval;
186 src += retval;
187 dst += retval;
188 len -= retval;
190 return copied;