/* * arch_ptrace() * architecture specific ptrace routine. */ long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: ret = generic_ptrace_peekdata(child, addr, data); break; /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; ret = -EIO; if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP) || (addr & 3)) break; tmp = 0; /* Default return condition */ ret = -EIO; if (addr < sizeof(struct pt_regs)) { tmp = ptrace_get_reg(child, addr); } else if (addr == PT_TEXT_ADDR) { tmp = child->mm->start_code; } else if (addr == PT_TEXT_END_ADDR) { tmp = child->mm->end_code; } else if (addr == PT_DATA_ADDR) { tmp = child->mm->start_data; } else if (addr == PT_EXEC_FDPIC_LOADMAP) { #ifdef CONFIG_BINFMT_ELF_FDPIC tmp = child->mm->context.exec_fdpic_loadmap; #endif } else if (addr == PT_INTERP_FDPIC_LOADMAP) { #ifdef CONFIG_BINFMT_ELF_FDPIC tmp = child->mm->context.interp_fdpic_loadmap; #endif } else { break; } ret = put_user(tmp, (unsigned long *)data); break; } case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); /* * If we just changed some code so we need to * correct the caches */ if (request == PTRACE_POKETEXT && ret == 0) { flush_icache_range(addr, addr + 4); } break; case PTRACE_POKEUSR: /* write the word at location addr * in the USER area */ ret = -EIO; if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3)) break; if (addr < sizeof(struct pt_regs)) { ret = ptrace_put_reg(child, addr, data); } break; case PTRACE_SYSCALL: /* continue and stop at next (return from) * syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -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; /* make sure the single step bit is not set. */ ptrace_disable_single_step(child); wake_up_process(child); ret = 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: { ret = 0; if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ ptrace_disable_single_step(child); wake_up_process(child); break; } case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break; case PTRACE_GETREGS: /* Get all gp regs from the child. */ ptrace_getregs(child, (unsigned long *)data); ret = 0; break; case PTRACE_SETREGS: { /* Set all gp regs in the child. */ int i; unsigned long tmp; int count = sizeof(struct pt_regs) / sizeof(unsigned long); for (i = 0; i < count; i++) { if (get_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } ptrace_put_reg(child, sizeof(unsigned long) * i, tmp); data += sizeof(long); } ret = 0; break; } default: return ptrace_request(child, request, addr, data); break; } return ret; }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret = -EPERM; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: ret = generic_ptrace_peekdata(child, addr, data); break; /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long index, tmp; ret = -EIO; /* convert to index and check */ #ifdef CONFIG_PPC32 index = (unsigned long) addr >> 2; if ((addr & 3) || (index > PT_FPSCR) || (child->thread.regs == NULL)) #else index = (unsigned long) addr >> 3; if ((addr & 7) || (index > PT_FPSCR)) #endif break; CHECK_FULL_REGS(child->thread.regs); if (index < PT_FPR0) { tmp = ptrace_get_reg(child, (int) index); } else { flush_fp_to_thread(child); tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; } ret = put_user(tmp,(unsigned long __user *) data); break; } /* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); break; /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: { unsigned long index; ret = -EIO; /* convert to index and check */ #ifdef CONFIG_PPC32 index = (unsigned long) addr >> 2; if ((addr & 3) || (index > PT_FPSCR) || (child->thread.regs == NULL)) #else index = (unsigned long) addr >> 3; if ((addr & 7) || (index > PT_FPSCR)) #endif break; CHECK_FULL_REGS(child->thread.regs); if (index < PT_FPR0) { ret = ptrace_put_reg(child, index, data); } else { flush_fp_to_thread(child); ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ret = 0; } break; } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -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; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); ret = 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: { ret = 0; if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); break; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_single_step(child); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); ret = 0; break; } case PTRACE_GET_DEBUGREG: { ret = -EINVAL; /* We only support one DABR and no IABRS at the moment */ if (addr > 0) break; ret = put_user(child->thread.dabr, (unsigned long __user *)data); break; } case PTRACE_SET_DEBUGREG: ret = ptrace_set_debugreg(child, addr, data); break; #ifdef CONFIG_PPC64 case PTRACE_GETREGS64: #endif case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ int ui; if (!access_ok(VERIFY_WRITE, (void __user *)data, sizeof(struct pt_regs))) { ret = -EIO; break; } CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret |= __put_user(ptrace_get_reg(child, ui), (unsigned long __user *) data); data += sizeof(long); } break; } #ifdef CONFIG_PPC64 case PTRACE_SETREGS64: #endif case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp; int ui; if (!access_ok(VERIFY_READ, (void __user *)data, sizeof(struct pt_regs))) { ret = -EIO; break; } CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret = __get_user(tmp, (unsigned long __user *) data); if (ret) break; ptrace_put_reg(child, ui, tmp); data += sizeof(long); } break; } case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */ flush_fp_to_thread(child); ret = get_fpregs((void __user *)data, child, 1); break; } case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */ flush_fp_to_thread(child); ret = set_fpregs((void __user *)data, child, 1); break; } #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: /* Get the child altivec register state. */ flush_altivec_to_thread(child); ret = get_vrregs((unsigned long __user *)data, child); break; case PTRACE_SETVRREGS: /* Set the child altivec register state. */ flush_altivec_to_thread(child); ret = set_vrregs(child, (unsigned long __user *)data); break; #endif #ifdef CONFIG_SPE case PTRACE_GETEVRREGS: /* Get the child spe register state. */ flush_spe_to_thread(child); ret = get_evrregs((unsigned long __user *)data, child); break; case PTRACE_SETEVRREGS: /* Set the child spe register state. */ /* this is to clear the MSR_SPE bit to force a reload * of register state from memory */ flush_spe_to_thread(child); ret = set_evrregs(child, (unsigned long __user *)data); break; #endif /* Old reverse args ptrace callss */ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */ ret = arch_ptrace_old(child, request, addr, data); break; default: ret = ptrace_request(child, request, addr, data); break; } return ret; }