diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 25 |
1 files changed, 10 insertions, 15 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 41e20763886..450931a45b6 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -170,8 +170,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); if (addr == (addr_t) &dummy->regs.psw.mask) /* Return a clean psw mask. */ - tmp = psw_user_bits | (tmp & PSW_MASK_USER) | - PSW_MASK_EA | PSW_MASK_BA; + tmp = psw_user_bits | (tmp & PSW_MASK_USER); } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { /* @@ -286,26 +285,17 @@ static inline void __poke_user_per(struct task_struct *child, static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t offset, tmp; + addr_t offset; if (addr < (addr_t) &dummy->regs.acrs) { /* * psw and gprs are stored on the stack */ - tmp = (data & ~PSW_MASK_USER) ^ psw_user_bits; if (addr == (addr_t) &dummy->regs.psw.mask && -#ifdef CONFIG_COMPAT - tmp != PSW_MASK_BA && -#endif - tmp != (PSW_MASK_EA | PSW_MASK_BA)) + ((data & ~PSW_MASK_USER) != psw_user_bits || + ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)))) /* Invalid psw mask. */ return -EINVAL; -#ifndef CONFIG_64BIT - if (addr == (addr_t) &dummy->regs.psw.addr) - /* I'd like to reject addresses without the - high order bit but older gdb's rely on it */ - data |= PSW_ADDR_AMODE; -#endif if (addr == (addr_t) &dummy->regs.psw.addr) /* * The debugger changed the instruction address, @@ -517,7 +507,8 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) tmp = psw32_user_bits | (tmp & PSW32_MASK_USER); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Fake a 31 bit psw address. */ - tmp = (__u32) regs->psw.addr | PSW32_ADDR_AMODE; + tmp = (__u32) regs->psw.addr | + (__u32)(regs->psw.mask & PSW_MASK_BA); } else { /* gpr 0-15 */ tmp = *(__u32 *)((addr_t) ®s->psw + addr*2 + 4); @@ -615,10 +606,14 @@ static int __poke_user_compat(struct task_struct *child, /* Invalid psw mask. */ return -EINVAL; regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | + (regs->psw.mask & PSW_MASK_BA) | (__u64)(tmp & PSW32_MASK_USER) << 32; } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Build a 64 bit psw address from 31 bit address. */ regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; + /* Transfer 31 bit amode bit to psw mask. */ + regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) | + (__u64)(tmp & PSW32_ADDR_AMODE); /* * The debugger changed the instruction address, * reset system call restart, see signal.c:do_signal |