Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb67e161 authored by Chris Metcalf's avatar Chris Metcalf
Browse files

arch/tile: provide PT_FLAGS_COMPAT value in pt_regs



This flag is set for ptrace GETREGS or PEEKUSER for processes
that are COMPAT, i.e. 32-bit.  This allows things like strace
to easily discover what personality to use, for example.

Acked-by: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarChris Metcalf <cmetcalf@tilera.com>
parent 17a26354
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -84,5 +84,11 @@ struct pt_regs {
#define PTRACE_O_TRACEMIGRATE	0x00010000
#define PTRACE_EVENT_MIGRATE	16

/*
 * Flag bits in pt_regs.flags that are part of the ptrace API.
 * We start our numbering higher up to avoid confusion with the
 * non-ABI kernel-internal values that use the low 16 bits.
 */
#define PT_FLAGS_COMPAT		0x10000  /* process is an -m32 compat process */

#endif /* _UAPI_ASM_TILE_PTRACE_H */
+40 −17
Original line number Diff line number Diff line
@@ -45,6 +45,41 @@ void ptrace_disable(struct task_struct *child)
	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}

/*
 * Get registers from task and ready the result for userspace.
 * Note that we localize the API issues to getregs() and putregs() at
 * some cost in performance, e.g. we need a full pt_regs copy for
 * PEEKUSR, and two copies for POKEUSR.  But in general we expect
 * GETREGS/PUTREGS to be the API of choice anyway.
 */
static char *getregs(struct task_struct *child, struct pt_regs *uregs)
{
	*uregs = *task_pt_regs(child);

	/* Set up flags ABI bits. */
	uregs->flags = 0;
#ifdef CONFIG_COMPAT
	if (task_thread_info(child)->status & TS_COMPAT)
		uregs->flags |= PT_FLAGS_COMPAT;
#endif

	return (char *)uregs;
}

/* Put registers back to task. */
static void putregs(struct task_struct *child, struct pt_regs *uregs)
{
	struct pt_regs *regs = task_pt_regs(child);

	/* Don't allow overwriting the kernel-internal flags word. */
	uregs->flags = regs->flags;

	/* Only allow setting the ICS bit in the ex1 word. */
	uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));

	*regs = *uregs;
}

long arch_ptrace(struct task_struct *child, long request,
		 unsigned long addr, unsigned long data)
{
@@ -53,14 +88,13 @@ long arch_ptrace(struct task_struct *child, long request,
	long ret = -EIO;
	char *childreg;
	struct pt_regs copyregs;
	int ex1_offset;

	switch (request) {

	case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
		if (addr >= PTREGS_SIZE)
			break;
		childreg = (char *)task_pt_regs(child) + addr;
		childreg = getregs(child, &copyregs) + addr;
#ifdef CONFIG_COMPAT
		if (is_compat_task()) {
			if (addr & (sizeof(compat_long_t)-1))
@@ -79,17 +113,7 @@ long arch_ptrace(struct task_struct *child, long request,
	case PTRACE_POKEUSR:  /* Write register in pt_regs. */
		if (addr >= PTREGS_SIZE)
			break;
		childreg = (char *)task_pt_regs(child) + addr;

		/* Guard against overwrites of the privilege level. */
		ex1_offset = PTREGS_OFFSET_EX1;
#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
		if (is_compat_task())   /* point at low word */
			ex1_offset += sizeof(compat_long_t);
#endif
		if (addr == ex1_offset)
			data = PL_ICS_EX1(USER_PL, EX1_ICS(data));

		childreg = getregs(child, &copyregs) + addr;
#ifdef CONFIG_COMPAT
		if (is_compat_task()) {
			if (addr & (sizeof(compat_long_t)-1))
@@ -102,11 +126,12 @@ long arch_ptrace(struct task_struct *child, long request,
				break;
			*(long *)childreg = data;
		}
		putregs(child, &copyregs);
		ret = 0;
		break;

	case PTRACE_GETREGS:  /* Get all registers from the child. */
		if (copy_to_user(datap, task_pt_regs(child),
		if (copy_to_user(datap, getregs(child, &copyregs),
				 sizeof(struct pt_regs)) == 0) {
			ret = 0;
		}
@@ -115,9 +140,7 @@ long arch_ptrace(struct task_struct *child, long request,
	case PTRACE_SETREGS:  /* Set all registers in the child. */
		if (copy_from_user(&copyregs, datap,
				   sizeof(struct pt_regs)) == 0) {
			copyregs.ex1 =
				PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
			*task_pt_regs(child) = copyregs;
			putregs(child, &copyregs);
			ret = 0;
		}
		break;