~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/ptrace.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.