aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-12-12 17:24:39 -0500
committerChris Metcalf <cmetcalf@tilera.com>2012-12-13 11:34:24 -0500
commitcb67e161bc947ab467657dda38168c2b2266f5bc (patch)
tree289e3905765484e8736a62f1a8a289d833e0960e /arch/tile
parent17a263540cebd4c615755300f34c695b15378a58 (diff)
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>
Diffstat (limited to 'arch/tile')
-rw-r--r--arch/tile/include/uapi/asm/ptrace.h6
-rw-r--r--arch/tile/kernel/ptrace.c57
2 files changed, 46 insertions, 17 deletions
diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h
index c717d0fec72..0d2208803b2 100644
--- a/arch/tile/include/uapi/asm/ptrace.h
+++ b/arch/tile/include/uapi/asm/ptrace.h
@@ -84,5 +84,11 @@ struct pt_regs {
84#define PTRACE_O_TRACEMIGRATE 0x00010000 84#define PTRACE_O_TRACEMIGRATE 0x00010000
85#define PTRACE_EVENT_MIGRATE 16 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#endif /* _UAPI_ASM_TILE_PTRACE_H */ 94#endif /* _UAPI_ASM_TILE_PTRACE_H */
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index e92e40527d6..64ba102c596 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -45,6 +45,41 @@ void ptrace_disable(struct task_struct *child)
45 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 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 */
55static 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. */
70static 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
48long arch_ptrace(struct task_struct *child, long request, 83long arch_ptrace(struct task_struct *child, long request,
49 unsigned long addr, unsigned long data) 84 unsigned long addr, unsigned long data)
50{ 85{
@@ -53,14 +88,13 @@ long arch_ptrace(struct task_struct *child, long request,
53 long ret = -EIO; 88 long ret = -EIO;
54 char *childreg; 89 char *childreg;
55 struct pt_regs copyregs; 90 struct pt_regs copyregs;
56 int ex1_offset;
57 91
58 switch (request) { 92 switch (request) {
59 93
60 case PTRACE_PEEKUSR: /* Read register from pt_regs. */ 94 case PTRACE_PEEKUSR: /* Read register from pt_regs. */
61 if (addr >= PTREGS_SIZE) 95 if (addr >= PTREGS_SIZE)
62 break; 96 break;
63 childreg = (char *)task_pt_regs(child) + addr; 97 childreg = getregs(child, &copyregs) + addr;
64#ifdef CONFIG_COMPAT 98#ifdef CONFIG_COMPAT
65 if (is_compat_task()) { 99 if (is_compat_task()) {
66 if (addr & (sizeof(compat_long_t)-1)) 100 if (addr & (sizeof(compat_long_t)-1))
@@ -79,17 +113,7 @@ long arch_ptrace(struct task_struct *child, long request,
79 case PTRACE_POKEUSR: /* Write register in pt_regs. */ 113 case PTRACE_POKEUSR: /* Write register in pt_regs. */
80 if (addr >= PTREGS_SIZE) 114 if (addr >= PTREGS_SIZE)
81 break; 115 break;
82 childreg = (char *)task_pt_regs(child) + addr; 116 childreg = getregs(child, &copyregs) + addr;
83
84 /* Guard against overwrites of the privilege level. */
85 ex1_offset = PTREGS_OFFSET_EX1;
86#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
87 if (is_compat_task()) /* point at low word */
88 ex1_offset += sizeof(compat_long_t);
89#endif
90 if (addr == ex1_offset)
91 data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
92
93#ifdef CONFIG_COMPAT 117#ifdef CONFIG_COMPAT
94 if (is_compat_task()) { 118 if (is_compat_task()) {
95 if (addr & (sizeof(compat_long_t)-1)) 119 if (addr & (sizeof(compat_long_t)-1))
@@ -102,11 +126,12 @@ long arch_ptrace(struct task_struct *child, long request,
102 break; 126 break;
103 *(long *)childreg = data; 127 *(long *)childreg = data;
104 } 128 }
129 putregs(child, &copyregs);
105 ret = 0; 130 ret = 0;
106 break; 131 break;
107 132
108 case PTRACE_GETREGS: /* Get all registers from the child. */ 133 case PTRACE_GETREGS: /* Get all registers from the child. */
109 if (copy_to_user(datap, task_pt_regs(child), 134 if (copy_to_user(datap, getregs(child, &copyregs),
110 sizeof(struct pt_regs)) == 0) { 135 sizeof(struct pt_regs)) == 0) {
111 ret = 0; 136 ret = 0;
112 } 137 }
@@ -115,9 +140,7 @@ long arch_ptrace(struct task_struct *child, long request,
115 case PTRACE_SETREGS: /* Set all registers in the child. */ 140 case PTRACE_SETREGS: /* Set all registers in the child. */
116 if (copy_from_user(&copyregs, datap, 141 if (copy_from_user(&copyregs, datap,
117 sizeof(struct pt_regs)) == 0) { 142 sizeof(struct pt_regs)) == 0) {
118 copyregs.ex1 = 143 putregs(child, &copyregs);
119 PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
120 *task_pt_regs(child) = copyregs;
121 ret = 0; 144 ret = 0;
122 } 145 }
123 break; 146 break;