#include <linux/user.h>
#include <linux/security.h>
#include <linux/audit.h>
+#include <linux/signal.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/unistd.h>
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
#include "compat_ptrace.h"
#endif
if (per_info->single_step) {
per_info->control_regs.bits.starting_addr = 0;
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_31BIT))
per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
else
clear_single_step(child);
}
-#ifndef CONFIG_ARCH_S390X
+#ifndef CONFIG_64BIT
# define __ADDR_MASK 3
#else
# define __ADDR_MASK 7
peek_user(struct task_struct *child, addr_t addr, addr_t data)
{
struct user *dummy = NULL;
- addr_t offset, tmp;
+ addr_t offset, tmp, mask;
/*
* Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell...
*/
- if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+ mask = __ADDR_MASK;
+#ifdef CONFIG_64BIT
+ if (addr >= (addr_t) &dummy->regs.acrs &&
+ addr < (addr_t) &dummy->regs.orig_gpr2)
+ mask = 3;
+#endif
+ if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) {
* access registers are stored in the thread structure
*/
offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_64BIT
+ /*
+ * 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...
+ */
+ if (addr == (addr_t) &dummy->regs.acrs[15])
+ tmp = ((unsigned long) child->thread.acrs[15]) << 32;
+ else
+#endif
tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
*/
offset = addr - (addr_t) &dummy->regs.fp_regs;
tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
+ if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
+ tmp &= (unsigned long) FPC_VALID_MASK
+ << (BITS_PER_LONG - 32);
} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
/*
poke_user(struct task_struct *child, addr_t addr, addr_t data)
{
struct user *dummy = NULL;
- addr_t offset;
+ addr_t offset, mask;
/*
* Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell indeed...
*/
- if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+ mask = __ADDR_MASK;
+#ifdef CONFIG_64BIT
+ if (addr >= (addr_t) &dummy->regs.acrs &&
+ addr < (addr_t) &dummy->regs.orig_gpr2)
+ mask = 3;
+#endif
+ if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) {
* psw and gprs are stored on the stack
*/
if (addr == (addr_t) &dummy->regs.psw.mask &&
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
#endif
data != PSW_MASK_MERGE(PSW_USER_BITS, data))
/* Invalid psw mask. */
return -EINVAL;
-#ifndef CONFIG_ARCH_S390X
+#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 */
* access registers are stored in the thread structure
*/
offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_64BIT
+ /*
+ * 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...
+ */
+ if (addr == (addr_t) &dummy->regs.acrs[15])
+ child->thread.acrs[15] = (unsigned int) (data >> 32);
+ else
+#endif
*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
* floating point regs. are stored in the thread structure
*/
if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
- (data & ~FPC_VALID_MASK) != 0)
+ (data & ~((unsigned long) FPC_VALID_MASK
+ << (BITS_PER_LONG - 32))) != 0)
return -EINVAL;
offset = addr - (addr_t) &dummy->regs.fp_regs;
*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
return ptrace_request(child, request, addr, data);
}
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
/*
* Now the fun part starts... a 31 bit program running in the
* 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
return peek_user(child, addr, data);
if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP)
return poke_user(child, addr, data);
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
if (request == PTRACE_PEEKUSR &&
addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
return peek_user_emu31(child, addr, data);
/* continue and stop at next (return from) syscall */
case PTRACE_CONT:
/* restart after signal. */
- if ((unsigned long) data >= _NSIG)
+ if (!valid_signal(data))
return -EIO;
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
case PTRACE_SINGLESTEP:
/* set the trap flag. */
- if ((unsigned long) data >= _NSIG)
+ if (!valid_signal(data))
return -EIO;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
/* Do requests that differ for 31/64 bit */
default:
-#ifdef CONFIG_S390_SUPPORT
+#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_31BIT))
return do_ptrace_emu31(child, request, addr, data);
#endif
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
+ /*
+ * If the debuffer has set an invalid system call number,
+ * we prepare to skip the system call restart handling.
+ */
+ if (!entryexit && regs->gprs[2] >= NR_syscalls)
+ regs->trap = -1;
+
/*
* this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the