Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

+46 -17
+6
arch/tile/include/uapi/asm/ptrace.h
··· 84 84 #define PTRACE_O_TRACEMIGRATE 0x00010000 85 85 #define PTRACE_EVENT_MIGRATE 16 86 86 87 + /* 88 + * Flag bits in pt_regs.flags that are part of the ptrace API. 89 + * We start our numbering higher up to avoid confusion with the 90 + * non-ABI kernel-internal values that use the low 16 bits. 91 + */ 92 + #define PT_FLAGS_COMPAT 0x10000 /* process is an -m32 compat process */ 87 93 88 94 #endif /* _UAPI_ASM_TILE_PTRACE_H */
+40 -17
arch/tile/kernel/ptrace.c
··· 45 45 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 46 46 } 47 47 48 + /* 49 + * Get registers from task and ready the result for userspace. 50 + * Note that we localize the API issues to getregs() and putregs() at 51 + * some cost in performance, e.g. we need a full pt_regs copy for 52 + * PEEKUSR, and two copies for POKEUSR. But in general we expect 53 + * GETREGS/PUTREGS to be the API of choice anyway. 54 + */ 55 + static char *getregs(struct task_struct *child, struct pt_regs *uregs) 56 + { 57 + *uregs = *task_pt_regs(child); 58 + 59 + /* Set up flags ABI bits. */ 60 + uregs->flags = 0; 61 + #ifdef CONFIG_COMPAT 62 + if (task_thread_info(child)->status & TS_COMPAT) 63 + uregs->flags |= PT_FLAGS_COMPAT; 64 + #endif 65 + 66 + return (char *)uregs; 67 + } 68 + 69 + /* Put registers back to task. */ 70 + static void putregs(struct task_struct *child, struct pt_regs *uregs) 71 + { 72 + struct pt_regs *regs = task_pt_regs(child); 73 + 74 + /* Don't allow overwriting the kernel-internal flags word. */ 75 + uregs->flags = regs->flags; 76 + 77 + /* Only allow setting the ICS bit in the ex1 word. */ 78 + uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1)); 79 + 80 + *regs = *uregs; 81 + } 82 + 48 83 long arch_ptrace(struct task_struct *child, long request, 49 84 unsigned long addr, unsigned long data) 50 85 { ··· 88 53 long ret = -EIO; 89 54 char *childreg; 90 55 struct pt_regs copyregs; 91 - int ex1_offset; 92 56 93 57 switch (request) { 94 58 95 59 case PTRACE_PEEKUSR: /* Read register from pt_regs. */ 96 60 if (addr >= PTREGS_SIZE) 97 61 break; 98 - childreg = (char *)task_pt_regs(child) + addr; 62 + childreg = getregs(child, &copyregs) + addr; 99 63 #ifdef CONFIG_COMPAT 100 64 if (is_compat_task()) { 101 65 if (addr & (sizeof(compat_long_t)-1)) ··· 113 79 case PTRACE_POKEUSR: /* Write register in pt_regs. */ 114 80 if (addr >= PTREGS_SIZE) 115 81 break; 116 - childreg = (char *)task_pt_regs(child) + addr; 117 - 118 - /* Guard against overwrites of the privilege level. */ 119 - ex1_offset = PTREGS_OFFSET_EX1; 120 - #if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN) 121 - if (is_compat_task()) /* point at low word */ 122 - ex1_offset += sizeof(compat_long_t); 123 - #endif 124 - if (addr == ex1_offset) 125 - data = PL_ICS_EX1(USER_PL, EX1_ICS(data)); 126 - 82 + childreg = getregs(child, &copyregs) + addr; 127 83 #ifdef CONFIG_COMPAT 128 84 if (is_compat_task()) { 129 85 if (addr & (sizeof(compat_long_t)-1)) ··· 126 102 break; 127 103 *(long *)childreg = data; 128 104 } 105 + putregs(child, &copyregs); 129 106 ret = 0; 130 107 break; 131 108 132 109 case PTRACE_GETREGS: /* Get all registers from the child. */ 133 - if (copy_to_user(datap, task_pt_regs(child), 110 + if (copy_to_user(datap, getregs(child, &copyregs), 134 111 sizeof(struct pt_regs)) == 0) { 135 112 ret = 0; 136 113 } ··· 140 115 case PTRACE_SETREGS: /* Set all registers in the child. */ 141 116 if (copy_from_user(&copyregs, datap, 142 117 sizeof(struct pt_regs)) == 0) { 143 - copyregs.ex1 = 144 - PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1)); 145 - *task_pt_regs(child) = copyregs; 118 + putregs(child, &copyregs); 146 119 ret = 0; 147 120 } 148 121 break;