summaryrefslogtreecommitdiffstats
path: root/arch/mips/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 /arch/mips/kernel/ptrace.c
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r--arch/mips/kernel/ptrace.c233
1 files changed, 12 insertions, 221 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index c8e3d23b6..68084ab3d 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1,4 +1,4 @@
-/* $Id: ptrace.c,v 1.15 1999/08/09 19:43:14 harald Exp $
+/* $Id: ptrace.c,v 1.16 1999/08/18 23:37:43 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -25,218 +25,6 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
- struct vm_area_struct * vma, unsigned long addr)
-{
- pgd_t *pgdir;
- pmd_t *pgmiddle;
- pte_t *pgtable;
- unsigned long page, retval;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (pgd_none(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return 0;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return 0;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- page = pte_page(*pgtable);
- /* This is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) >= MAP_NR(high_memory))
- return 0;
- page += addr & ~PAGE_MASK;
- /* We can't use flush_page_to_ram() since we're running in
- * another context ...
- */
- flush_cache_all();
- retval = *(unsigned long *) page;
- flush_cache_all(); /* VCED avoidance */
- return retval;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it. -M.U-
- */
-static void put_long(struct task_struct *tsk,
- struct vm_area_struct * vma, unsigned long addr,
- unsigned long data)
-{
- pgd_t *pgdir;
- pmd_t *pgmiddle;
- pte_t *pgtable;
- unsigned long page;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (!pgd_present(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- page = pte_page(*pgtable);
- if (!pte_write(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- /* This is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) < MAP_NR(high_memory))
- flush_cache_all();
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
- if (MAP_NR(page) < MAP_NR(high_memory))
- flush_cache_all();
- /*
- * We're bypassing pagetables, so we have to set the dirty bit
- * ourselves this should also re-instate whatever read-only mode
- * there was before
- */
- set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
- unsigned long * result)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
- high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 1:
- low >>= 8;
- low |= high << 24;
- break;
- case 2:
- low >>= 16;
- low |= high << 16;
- break;
- case 3:
- low >>= 24;
- low |= high << 8;
- break;
- }
- *result = low;
- } else
- *result = get_long(tsk, vma, addr);
- return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
- unsigned long data)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
- high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 0: /* shouldn't happen, but safety first */
- low = data;
- break;
- case 1:
- low &= 0x000000ff;
- low |= data << 8;
- high &= ~0xff;
- high |= data >> 24;
- break;
- case 2:
- low &= 0x0000ffff;
- low |= data << 16;
- high &= ~0xffff;
- high |= data >> 16;
- break;
- case 3:
- low &= 0x00ffffff;
- low |= data << 24;
- high &= ~0xffffff;
- high |= data >> 8;
- break;
- }
- put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
- put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
- } else
- put_long(tsk, vma, addr, data);
- return 0;
-}
-
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -323,15 +111,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ int copied;
- down(&child->mm->mmap_sem);
- res = read_long(child, addr, &tmp);
- up(&child->mm->mmap_sem);
- if (res < 0)
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ res = -EIO;
+ if (copied != sizeof(tmp))
goto out;
res = put_user(tmp,(unsigned long *) data);
+
goto out;
- }
+ }
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -397,9 +186,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- down(&child->mm->mmap_sem);
- res = write_long(child,addr,data);
- up(&child->mm->mmap_sem);
+ res = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1)
+ == sizeof(data))
+ goto out;
+ res = -EIO;
goto out;
case PTRACE_POKEUSR: {