long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int rval; unsigned long val = 0; switch (request) { /* Read/write the word at location ADDR in the registers. */ case PTRACE_PEEKUSR: case PTRACE_POKEUSR: pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr); rval = 0; if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) { /* * Special requests that don't actually correspond * to offsets in struct pt_regs. */ if (addr == PT_TEXT_ADDR) { val = child->mm->start_code; } else if (addr == PT_DATA_ADDR) { val = child->mm->start_data; } else if (addr == PT_TEXT_LEN) { val = child->mm->end_code - child->mm->start_code; } else { rval = -EIO; } } else if (addr < PT_SIZE && (addr & 0x3) == 0) { microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) val = *reg_addr; else { #if 1 *reg_addr = data; #else /* MS potential problem on WB system * Be aware that reg_addr is virtual address * virt_to_phys conversion is necessary. * This could be sensible solution. */ u32 paddr = virt_to_phys((u32)reg_addr); invalidate_icache_range(paddr, paddr + 4); *reg_addr = data; flush_dcache_range(paddr, paddr + 4); #endif } } else rval = -EIO; if (rval == 0 && request == PTRACE_PEEKUSR) rval = put_user(val, (unsigned long __user *)data); break; default: rval = ptrace_request(child, request, addr, data); } return rval; }
/* Try to set CHILD's single-step flag to VAL. Returns true if successful. */ static int set_single_step (struct task_struct *t, int val) { microblaze_reg_t *sstep_addr = reg_save_addr(PT_SINGLESTEP, t); if (val) { /* Make sure single-stepping is enabled. */ if (! enable_single_stepping ()) return 0; /* Set T's single-step flag. */ *sstep_addr = 1; } else *sstep_addr = 0; return 1; }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int rval; unsigned long val = 0; switch (request) { /* Read/write the word at location ADDR in the registers. */ case PTRACE_PEEKUSR: case PTRACE_POKEUSR: pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr); rval = 0; if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) { /* * Special requests that don't actually correspond * to offsets in struct pt_regs. */ if (addr == PT_TEXT_ADDR) { val = child->mm->start_code; } else if (addr == PT_DATA_ADDR) { val = child->mm->start_data; } else if (addr == PT_TEXT_LEN) { val = child->mm->end_code - child->mm->start_code; } else { rval = -EIO; } } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) val = *reg_addr; else *reg_addr = data; } else rval = -EIO; if (rval == 0 && request == PTRACE_PEEKUSR) rval = put_user(val, (unsigned long *)data); break; default: rval = ptrace_request(child, request, addr, data); } return rval; }
int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int rval; lock_kernel(); /* printk("sys_ptrace - PID:%u ADDR:%08x DATA:%08x\n",pid,addr,data); */ if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { rval = -EPERM; goto out; } /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; rval = 0; goto out; } rval = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; rval = -EPERM; if (pid == 1) /* you may not mess with init */ goto out; if (request == PTRACE_ATTACH) { rval = ptrace_attach(child); goto out_tsk; } rval = -ESRCH; if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) goto out_tsk; } if (child->p_pptr != current) goto out_tsk; switch (request) { unsigned long val, copied; case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: /* printk("PEEKTEXT/PEEKDATA at %08X\n",addr); */ copied = access_process_vm(child, addr, &val, sizeof(val), 0); rval = -EIO; if (copied != sizeof(val)) break; rval = put_user(val, (unsigned long *)data); goto out; case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: /* printk("POKETEXT/POKEDATA to %08X\n",addr); */ rval = 0; if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; rval = -EIO; goto out; /* Read/write the word at location ADDR in the registers. */ case PTRACE_PEEKUSR: case PTRACE_POKEUSR: rval = 0; if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) { /* Special requests that don't actually correspond to offsets in struct pt_regs. */ if (addr == PT_TEXT_ADDR) { val = child->mm->start_code; } else if (addr == PT_DATA_ADDR) { val = child->mm->start_data; } else if (addr == PT_TEXT_LEN) { val = child->mm->end_code - child->mm->start_code; } else if (addr == PT_DATA_LEN) { val = child->mm->end_data - child->mm->start_data; } else { rval = -EIO; } } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) { val = *reg_addr; } else { *reg_addr = data; } } else rval = -EIO; if (rval == 0 && request == PTRACE_PEEKUSR) { rval = put_user (val, (unsigned long *)data); } goto out; /* Continue and stop at next (return from) syscall */ case PTRACE_SYSCALL: /* Restart after a signal. */ case PTRACE_CONT: /* printk("PTRACE_CONT\n"); */ /* Execute a single instruction. */ case PTRACE_SINGLESTEP: /* printk("PTRACE_SINGLESTEP\n"); */ rval = -EIO; if ((unsigned long) data > _NSIG) break; /* Turn CHILD's single-step flag on or off. */ /* printk("calling set_single_step\n"); */ if (! set_single_step (child, request == PTRACE_SINGLESTEP)) break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* printk("wakeup_process\n"); */ wake_up_process(child); rval = 0; break; /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: /* printk("PTRACE_KILL\n"); */ rval = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; wake_up_process(child); break; case PTRACE_DETACH: /* detach a process that was attached. */ /* printk("PTRACE_DETACH\n"); */ set_single_step (child, 0); /* Clear single-step flag */ rval = ptrace_detach(child, data); break; default: rval = -EIO; goto out; } out_tsk: free_task_struct(child); out: unlock_kernel(); return rval; }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int rval; unsigned long val = 0; unsigned long copied; switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr); copied = access_process_vm(child, addr, &val, sizeof(val), 0); rval = -EIO; if (copied != sizeof(val)) break; rval = put_user(val, (unsigned long *)data); break; case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: pr_debug("POKETEXT/POKEDATA to %08lX\n", addr); rval = 0; if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; rval = -EIO; break; /* Read/write the word at location ADDR in the registers. */ case PTRACE_PEEKUSR: case PTRACE_POKEUSR: pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr); rval = 0; if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) { /* * Special requests that don't actually correspond * to offsets in struct pt_regs. */ if (addr == PT_TEXT_ADDR) { val = child->mm->start_code; } else if (addr == PT_DATA_ADDR) { val = child->mm->start_data; } else if (addr == PT_TEXT_LEN) { val = child->mm->end_code - child->mm->start_code; } else { rval = -EIO; } } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) val = *reg_addr; else *reg_addr = data; } else rval = -EIO; if (rval == 0 && request == PTRACE_PEEKUSR) rval = put_user(val, (unsigned long *)data); break; /* Continue and stop at next (return from) syscall */ case PTRACE_SYSCALL: pr_debug("PTRACE_SYSCALL\n"); case PTRACE_SINGLESTEP: pr_debug("PTRACE_SINGLESTEP\n"); /* Restart after a signal. */ case PTRACE_CONT: pr_debug("PTRACE_CONT\n"); rval = -EIO; if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; pr_debug("wakeup_process\n"); wake_up_process(child); rval = 0; break; /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: pr_debug("PTRACE_KILL\n"); rval = 0; if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; wake_up_process(child); break; case PTRACE_DETACH: /* detach a process that was attached. */ pr_debug("PTRACE_DETACH\n"); rval = ptrace_detach(child, data); break; default: /* rval = ptrace_request(child, request, addr, data); noMMU */ rval = -EIO; } return rval; }