[PATCH 4c] utrace: s390 ptrace compatibility This patch implements ptrace compatibility for s390. Signed-off-by: Roland McGrath Signed-off-by: David Wilder --- arch/s390/kernel/compat_wrapper.S | 2 arch/s390/kernel/ptrace.c | 155 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) Index: b/arch/s390/kernel/ptrace.c =================================================================== --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -595,6 +595,161 @@ const struct utrace_regset_view *utrace_ } +#ifdef CONFIG_PTRACE +static const struct ptrace_layout_segment s390_uarea[] = { + {PT_PSWMASK, PT_FPC, 0, 0}, + {PT_FPC, PT_CR_9, 1, 0}, + {PT_CR_9, PT_IEEE_IP, 2, 0}, + {PT_IEEE_IP, sizeof(struct user), -1, -1}, + {0, 0, -1, 0} +}; + +int arch_ptrace(long *request, struct task_struct *child, + struct utrace_attached_engine *engine, + unsigned long addr, unsigned long data, long *val) +{ + ptrace_area parea; + unsigned long tmp; + int copied; + + switch (*request) { + case PTRACE_PEEKUSR: +#ifdef CONFIG_64BIT + /* + * Stupid gdb peeks/pokes the access registers in 64 bit with + * an alignment of 4. Programmers from hell... + */ + if (addr >= PT_ACR0 && addr < PT_ACR15) { + if (addr & 3) + return -EIO; + tmp = *(unsigned long *) + ((char *) child->thread.acrs + addr - PT_ACR0); + return put_user(tmp, (unsigned long __user *) data); + } + else if (addr == PT_ACR15) { + /* + * Very special case: old & broken 64 bit gdb reading + * from acrs[15]. Result is a 64 bit value. Read the + * 32 bit acrs[15] value and shift it by 32. Sick... + */ + tmp = ((unsigned long) child->thread.acrs[15]) << 32; + return put_user(tmp, (unsigned long __user *) data); + } +#endif + return ptrace_peekusr(child, engine, s390_uarea, addr, data); + case PTRACE_POKEUSR: +#ifdef CONFIG_64BIT + if (addr >= PT_ACR0 && addr < PT_ACR15) { + if (addr & 3) + return -EIO; + *(unsigned long *) ((char *) child->thread.acrs + + addr - PT_ACR0) = data; + return 0; + } + else if (addr == PT_ACR15) { + /* + * Very special case: old & broken 64 bit gdb writing + * to acrs[15] with a 64 bit value. Ignore the lower + * half of the value and write the upper 32 bit to + * acrs[15]. Sick... + */ + child->thread.acrs[15] = data >> 32; + return 0; + } +#endif + return ptrace_pokeusr(child, engine, s390_uarea, addr, data); + + case PTRACE_PEEKUSR_AREA: + case PTRACE_POKEUSR_AREA: + if (copy_from_user(&parea, (ptrace_area __user *) addr, + sizeof(parea))) + return -EFAULT; + if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1)) + return -EIO; + return ptrace_layout_access(child, engine, + utrace_native_view(current), + s390_uarea, + parea.kernel_addr, parea.len, + (void __user *) parea.process_addr, + NULL, + *request == PTRACE_POKEUSR_AREA); + + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + /* Remove high order bit from address (only for 31 bit). */ + addr &= PSW_ADDR_INSN; + /* read word at location addr. */ + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (copied != sizeof(tmp)) + return -EIO; + return put_user(tmp, (unsigned long __user *) data); + + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + /* Remove high order bit from address (only for 31 bit). */ + addr &= PSW_ADDR_INSN; + /* write the word at location addr. */ + copied = access_process_vm(child, addr, &data, sizeof(data),1); + if (copied != sizeof(data)) + return -EIO; + return 0; + } + + return -ENOSYS; +} + +#ifdef CONFIG_COMPAT +static const struct ptrace_layout_segment s390_compat_uarea[] = { + { offsetof(struct user_regs_struct32, psw), + offsetof(struct user_regs_struct32, fp_regs), 0, 0 }, + { offsetof(struct user_regs_struct32, fp_regs), + offsetof(struct user_regs_struct32, per_info), 1, 0 }, + { offsetof(struct user_regs_struct32, per_info), + offsetof(struct user_regs_struct32, ieee_instruction_pointer), 2, 0 }, + { offsetof(struct user_regs_struct32, ieee_instruction_pointer), + sizeof(struct user32), -1, -1 }, + { 0, 0, -1, 0 } +}; + +int arch_compat_ptrace(compat_long_t *request, + struct task_struct *child, + struct utrace_attached_engine *engine, + compat_ulong_t addr, compat_ulong_t data, + compat_long_t *val) +{ + ptrace_area_emu31 parea; + + switch (*request) { + case PTRACE_PEEKUSR: + return ptrace_compat_peekusr(child, engine, s390_compat_uarea, + addr, data); + case PTRACE_POKEUSR: + return ptrace_compat_pokeusr(child, engine, s390_compat_uarea, + addr, data); + case PTRACE_PEEKUSR_AREA: + case PTRACE_POKEUSR_AREA: + if (copy_from_user(&parea, ((ptrace_area_emu31 __user *) + (unsigned long) addr), + sizeof(parea))) + return -EFAULT; + if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1)) + return -EIO; + return ptrace_layout_access(child, engine, + utrace_native_view(current), + s390_compat_uarea, + parea.kernel_addr, parea.len, + (void __user *) + (unsigned long) parea.process_addr, + NULL, + *request == PTRACE_POKEUSR_AREA); + } + + return -ENOSYS; +} +#endif /* CONFIG_COMPAT */ +#endif /* CONFIG_PTRACE */ + + asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) { Index: b/arch/s390/kernel/compat_wrapper.S =================================================================== --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -121,7 +121,7 @@ sys32_ptrace_wrapper: lgfr %r3,%r3 # long llgtr %r4,%r4 # long llgfr %r5,%r5 # long - jg sys_ptrace # branch to system call + jg compat_sys_ptrace # branch to system call .globl sys32_alarm_wrapper sys32_alarm_wrapper: