X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fm68k%2Fkernel%2Fptrace.c;h=deddf39208236343197363ce97d546c33114a39c;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=1e143b4678ac74e8cc5d3579babd70efa6ab50ac;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 1e143b467..deddf3920 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,7 @@ static inline int put_reg(struct task_struct *task, int regno, if (regno == PT_USP) addr = &task->thread.usp; else if (regno < sizeof(regoff)/sizeof(regoff[0])) - addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); else return -1; *addr = data; @@ -102,285 +103,193 @@ static inline int put_reg(struct task_struct *task, int regno, } /* - * Called by kernel/ptrace.c when detaching.. - * * Make sure the single step bit is not set. */ -void ptrace_disable(struct task_struct *child) +static inline void singlestep_disable(struct task_struct *child) { - unsigned long tmp; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - child->thread.work.delayed_trace = 0; - child->thread.work.syscall_trace = 0; + clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); } -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +/* + * Called by kernel/ptrace.c when detaching.. + */ +void ptrace_disable(struct task_struct *child) { - struct task_struct *child; - int ret; - - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -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; - if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) - goto out_tsk; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } + singlestep_disable(child); + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); +} - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + unsigned long tmp; + int i, ret = 0; 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: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long *) data); - break; - } + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + i = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (i != sizeof(tmp)) + goto out_eio; + ret = put_user(tmp, (unsigned long *)data); + break; /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) - break; - - tmp = 0; /* Default return condition */ - addr = addr >> 2; /* temporary hack. */ - ret = -EIO; - if (addr < 19) { - tmp = get_reg(child, addr); - if (addr == PT_SR) - tmp >>= 16; - } else if (addr >= 21 && addr < 49) { - tmp = child->thread.fp[addr - 21]; -#ifdef CONFIG_M68KFPU_EMU - /* Convert internal fpu reg representation - * into long double format - */ - if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) - tmp = ((tmp & 0xffff0000) << 15) | - ((tmp & 0x0000ffff) << 16); -#endif - } else - break; - ret = put_user(tmp,(unsigned long *) data); - break; - } - - /* when 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 = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - break; - ret = -EIO; - break; - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) - break; - - addr = addr >> 2; /* temporary hack. */ - - if (addr == PT_SR) { - data &= SR_MASK; - data <<= 16; - data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - if (addr < 19) { - if (put_reg(child, addr, data)) - break; - ret = 0; - break; - } - if (addr >= 21 && addr < 48) - { -#ifdef CONFIG_M68KFPU_EMU - /* Convert long double format - * into internal fpu reg representation - */ - if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { - data = (unsigned long)data << 15; - data = (data & 0xffff0000) | - ((data & 0x0000ffff) >> 1); - } -#endif - child->thread.fp[addr - 21] = data; - ret = 0; - } + case PTRACE_PEEKUSR: + if (addr & 3) + goto out_eio; + addr >>= 2; /* temporary hack. */ + + if (addr >= 0 && addr < 19) { + tmp = get_reg(child, addr); + if (addr == PT_SR) + tmp >>= 16; + } else if (addr >= 21 && addr < 49) { + tmp = child->thread.fp[addr - 21]; + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); + } else break; - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - long tmp; - - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - if (request == PTRACE_SYSCALL) { - child->thread.work.syscall_trace = ~0; - } else { - child->thread.work.syscall_trace = 0; + ret = put_user(tmp, (unsigned long *)data); + break; + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data)) + goto out_eio; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + if (addr & 3) + goto out_eio; + addr >>= 2; /* temporary hack. */ + + if (addr == PT_SR) { + data &= SR_MASK; + data <<= 16; + data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } else if (addr >= 0 && addr < 19) { + if (put_reg(child, addr, data)) + goto out_eio; + } else if (addr >= 21 && addr < 48) { + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); } - child->exit_code = data; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); - put_reg(child, PT_SR, tmp); - child->thread.work.delayed_trace = 0; - 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: { - long tmp; - - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); - put_reg(child, PT_SR, tmp); - child->thread.work.delayed_trace = 0; - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; - - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - child->thread.work.syscall_trace = 0; - tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); - put_reg(child, PT_SR, tmp); - child->thread.work.delayed_trace = 1; - - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } + child->thread.fp[addr - 21] = data; + } else + goto out_eio; + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* restart after signal. */ + if (!valid_signal(data)) + goto out_eio; + + 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; + singlestep_disable(child); + wake_up_process(child); + break; - case PTRACE_DETACH: /* detach a process that was attached. */ - ret = ptrace_detach(child, data); + /* + * 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: + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - if (i == PT_SR) + child->exit_code = SIGKILL; + singlestep_disable(child); + wake_up_process(child); + break; + + case PTRACE_SINGLESTEP: /* set the trap flag. */ + if (!valid_signal(data)) + goto out_eio; + + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + set_tsk_thread_flag(child, TIF_DELAYED_TRACE); + + child->exit_code = data; + /* give it a chance to run. */ + 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. */ + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (i == PT_SR) tmp >>= 16; - if (put_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; + ret = put_user(tmp, (unsigned long *)data); + if (ret) break; - } - data += sizeof(long); - } - ret = 0; - break; + data += sizeof(long); } + break; - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - if (get_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + for (i = 0; i < 19; i++) { + ret = get_user(tmp, (unsigned long *)data); + if (ret) break; - } - if (i == PT_SR) { + if (i == PT_SR) { tmp &= SR_MASK; tmp <<= 16; tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - put_reg(child, i, tmp); - data += sizeof(long); } - ret = 0; - break; + put_reg(child, i, tmp); + data += sizeof(long); } - - case PTRACE_GETFPREGS: { /* Get the child FPU state. */ - ret = 0; - if (copy_to_user((void *)data, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } - - case PTRACE_SETFPREGS: { /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->thread.fp, (void *)data, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } - - default: - ret = ptrace_request(child, request, addr, data); - break; + break; + + case PTRACE_GETFPREGS: /* Get the child FPU state. */ + if (copy_to_user((void *)data, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_SETFPREGS: /* Set the child FPU state. */ + if (copy_from_user(&child->thread.fp, (void *)data, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; + return ret; +out_eio: + return -EIO; } asmlinkage void syscall_trace(void) { - if (!current->thread.work.delayed_trace && - !current->thread.work.syscall_trace) - return; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /*