summaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
commit0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch)
tree5085c389f09da78182b899d19fe1068b619a69dd /kernel/ptrace.c
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
new file mode 100644
index 000000000..0d007d492
--- /dev/null
+++ b/kernel/ptrace.c
@@ -0,0 +1,163 @@
+/*
+ * linux/kernel/ptrace.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Common interfaces for "ptrace()" which we do not want
+ * to continually duplicate across every architecture.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Access another process' address space, one page at a time.
+ */
+static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+{
+ pgd_t * pgdir;
+ pmd_t * pgmiddle;
+ pte_t * pgtable;
+ unsigned long page;
+
+repeat:
+ pgdir = pgd_offset(vma->vm_mm, addr);
+ if (pgd_none(*pgdir))
+ goto fault_in_page;
+ if (pgd_bad(*pgdir))
+ goto bad_pgd;
+ pgmiddle = pmd_offset(pgdir, addr);
+ if (pmd_none(*pgmiddle))
+ goto fault_in_page;
+ if (pmd_bad(*pgmiddle))
+ goto bad_pmd;
+ pgtable = pte_offset(pgmiddle, addr);
+ if (!pte_present(*pgtable))
+ goto fault_in_page;
+ page = pte_page(*pgtable);
+ if (MAP_NR(page) >= max_mapnr)
+ return 0;
+ flush_cache_page(vma, addr);
+ {
+ void *src = (void *) (page + (addr & ~PAGE_MASK));
+ void *dst = buf;
+
+ if (write) {
+ dst = src;
+ src = buf;
+ }
+ memcpy(dst, src, len);
+ }
+ flush_page_to_ram(page);
+ return len;
+
+fault_in_page:
+ /* -1: out of memory. 0 - unmapped page */
+ if (handle_mm_fault(tsk, vma, addr, write) > 0)
+ goto repeat;
+ return 0;
+
+bad_pgd:
+ printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
+ return 0;
+
+bad_pmd:
+ printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
+ return 0;
+}
+
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+ int copied;
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+ if (!vma)
+ return 0;
+
+ down(&tsk->mm->mmap_sem);
+ copied = 0;
+ for (;;) {
+ unsigned long offset = addr & ~PAGE_MASK;
+ int this_len = PAGE_SIZE - offset;
+ int retval;
+
+ if (this_len > len)
+ this_len = len;
+ retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+ copied += retval;
+ if (retval != this_len)
+ break;
+
+ len -= retval;
+ if (!len)
+ break;
+
+ addr += retval;
+ buf += retval;
+
+ if (addr < vma->vm_end)
+ continue;
+ if (!vma->vm_next)
+ break;
+ if (vma->vm_next->vm_start != vma->vm_end)
+ break;
+
+ vma = vma->vm_next;
+ }
+ up(&tsk->mm->mmap_sem);
+ return copied;
+}
+
+int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
+{
+ int copied = 0;
+
+ while (len > 0) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ retval = access_process_vm(tsk, src, buf, this_len, 0);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ if (copy_to_user(dst, buf, retval))
+ return -EFAULT;
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}
+
+int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
+{
+ int copied = 0;
+
+ while (len > 0) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ if (copy_from_user(buf, src, this_len))
+ return -EFAULT;
+ retval = access_process_vm(tsk, dst, buf, this_len, 1);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}