patch-2.2.18 linux/arch/arm/kernel/ptrace.c
Next file: linux/arch/arm/kernel/setup.c
Previous file: linux/arch/arm/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 250
- Date:
Fri Sep 15 23:28:37 2000
- Orig file:
v2.2.17/arch/arm/kernel/ptrace.c
- Orig date:
Fri Apr 21 12:45:45 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
@@ -25,6 +25,17 @@
* Breakpoint SWI instruction: SWI &9F0001
*/
#define BREAKINST 0xef9f0001
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+
+static inline struct pt_regs *
+get_user_regs(struct task_struct *task)
+{
+ return (struct pt_regs *)
+ ((unsigned long)task + 8192 - sizeof(struct pt_regs));
+}
/*
* this routine will get a word off of the processes privileged stack.
@@ -34,11 +45,7 @@
*/
static inline long get_stack_long(struct task_struct *task, int offset)
{
- unsigned char *stack;
-
- stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
- stack += offset << 2;
- return *(unsigned long *)stack;
+ return get_user_regs(task)->uregs[offset];
}
/*
@@ -47,15 +54,21 @@
* this routine assumes that all the privileged stacks are in our
* data space.
*/
-static inline long put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
+static inline int
+put_stack_long(struct task_struct *task, int offset, long data)
{
- unsigned char *stack;
+ struct pt_regs newregs, *regs = get_user_regs(task);
+ int ret = -EINVAL;
- stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
- stack += offset << 2;
- *(unsigned long *) stack = data;
- return 0;
+ newregs = *regs;
+ newregs.uregs[offset] = data;
+
+ if (valid_user_regs(&newregs)) {
+ regs->uregs[offset] = data;
+ ret = 0;
+ }
+
+ return ret;
}
/*
@@ -71,39 +84,42 @@
pmd_t *pgmiddle;
pte_t *pgtable;
unsigned long page;
+ int fault;
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
- if (pgd_none(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
+ if (pgd_none(*pgdir))
+ goto none;
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_none(*pgmiddle))
+ goto none;
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;
- }
+ if (!pte_present(*pgtable))
+ goto none;
page = pte_page(*pgtable);
if(MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
return *(unsigned long *)page;
+
+none:
+ fault = handle_mm_fault(tsk, vma, addr, 0);
+ if (fault > 0)
+ goto repeat;
+ if (fault < 0)
+ force_sig(SIGKILL, tsk);
+ return 0;
}
/*
@@ -122,46 +138,52 @@
pmd_t *pgmiddle;
pte_t *pgtable;
unsigned long page;
+ int fault;
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
- if (!pgd_present(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
+ if (!pgd_present(*pgdir))
+ goto none;
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_none(*pgmiddle))
+ goto none;
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;
- }
+ if (!pte_present(*pgtable))
+ goto none;
page = pte_page(*pgtable);
- if (!pte_write(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
+ if (!pte_write(*pgtable))
+ goto none;
if (MAP_NR(page) < max_mapnr) {
page += addr & ~PAGE_MASK;
+
+ flush_cache_range(vma->vm_mm, addr, addr + sizeof(unsigned long));
+
*(unsigned long *)page = data;
- __flush_entry_to_ram(page);
+
+ clean_cache_area(page, sizeof(unsigned long));
+
+ set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+ flush_tlb_page(vma, addr & PAGE_MASK);
}
- set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- flush_tlb();
+ return;
+
+none:
+ fault = handle_mm_fault(tsk, vma, addr, 1);
+ if (fault > 0)
+ goto repeat;
+ if (fault < 0)
+ force_sig(SIGKILL, tsk);
}
static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
@@ -669,7 +691,6 @@
return 0;
wake_up_process (child);
child->exit_code = SIGKILL;
- ptrace_cancel_bpt (child);
/* make sure single-step breakpoint is gone. */
ptrace_cancel_bpt (child);
ret = 0;
@@ -685,6 +706,54 @@
child->exit_code = data;
/* give it a chance to run. */
ret = 0;
+ goto out;
+
+ case PTRACE_GETREGS:
+ { /* Get all gp regs from the child. */
+ unsigned char *stack;
+
+ ret = 0;
+ stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
+ if (copy_to_user((void *)data, stack,
+ sizeof(struct pt_regs)))
+ ret = -EFAULT;
+
+ goto out;
+ };
+
+ /* Set all gp regs in the child. */
+ case PTRACE_SETREGS:
+ {
+ struct pt_regs newregs;
+
+ ret = -EFAULT;
+ if (copy_from_user(&newregs, (void *)data,
+ sizeof(struct pt_regs)) == 0) {
+ struct pt_regs *regs = get_user_regs(child);
+
+ ret = -EINVAL;
+ if (valid_user_regs(&newregs)) {
+ *regs = newregs;
+ ret = 0;
+ }
+ }
+ goto out;
+ }
+
+ case PTRACE_GETFPREGS:
+ /* Get the child FPU state. */
+ ret = 0;
+ if (copy_to_user((void *)data, &child->tss.fpstate,
+ sizeof(struct user_fp)))
+ ret = -EFAULT;
+ goto out;
+
+ case PTRACE_SETFPREGS:
+ /* Set the child FPU state. */
+ ret = 0;
+ if (copy_from_user(&child->tss.fpstate, (void *)data,
+ sizeof(struct user_fp)))
+ ret = -EFAULT;
goto out;
case PTRACE_DETACH: /* detach a process that was attached. */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)