aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorAndreas Schwab <schwab@linux-m68k.org>2009-05-19 09:38:01 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2009-12-04 15:22:35 -0500
commitf195e2bff3000b8bc251ee6f685e0f027eec6f25 (patch)
tree6a872faedca9f07af26b7ba90551258a10a3bd94 /arch/m68k
parentfaa47b466935e73251b18b17d51455b06ed65764 (diff)
m68k: ptrace fixes
This fixes the following issues in ptrace: - when single stepping into the signal handler stop at the first insn of the handler - handle non-zero stkadj when accessing pc and sr in ptregs - correctly handle PT_SR in PTRACE_POKEUSR - report -EIO when trying to read unknown offset in PTRACE_PEEKUSR Additionally, the handling of the special case that PT_SR accesses a 16 bit word instead of a 32 bit word has been moved into get_reg/put_reg. Signed-off-by: Andreas Schwab <schwab@linux-m68k.org> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/kernel/entry.S6
-rw-r--r--arch/m68k/kernel/ptrace.c45
2 files changed, 34 insertions, 17 deletions
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index c5b33634c980..77fc7c16bf48 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -179,7 +179,11 @@ do_signal_return:
179 addql #8,%sp 179 addql #8,%sp
180 RESTORE_SWITCH_STACK 180 RESTORE_SWITCH_STACK
181 addql #4,%sp 181 addql #4,%sp
182 jbra resume_userspace 182 tstl %d0
183 jeq resume_userspace
184 | when single stepping into handler stop at the first insn
185 btst #6,%curptr@(TASK_INFO+TINFO_FLAGS+2)
186 jeq resume_userspace
183 187
184do_delayed_trace: 188do_delayed_trace:
185 bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR 189 bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index bd0842059d11..1fc217e5f06b 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -46,7 +46,7 @@
46/* Mapping from PT_xxx to the stack offset at which the register is 46/* Mapping from PT_xxx to the stack offset at which the register is
47 saved. Notice that usp has no stack-slot and needs to be treated 47 saved. Notice that usp has no stack-slot and needs to be treated
48 specially (see get_reg/put_reg below). */ 48 specially (see get_reg/put_reg below). */
49static int regoff[] = { 49static const int regoff[] = {
50 [0] = PT_REG(d1), 50 [0] = PT_REG(d1),
51 [1] = PT_REG(d2), 51 [1] = PT_REG(d2),
52 [2] = PT_REG(d3), 52 [2] = PT_REG(d3),
@@ -81,6 +81,14 @@ static inline long get_reg(struct task_struct *task, int regno)
81 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); 81 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
82 else 82 else
83 return 0; 83 return 0;
84 /* Need to take stkadj into account. */
85 if (regno == PT_SR || regno == PT_PC) {
86 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
87 addr = (unsigned long *) ((unsigned long)addr + stkadj);
88 /* The sr is actually a 16 bit register. */
89 if (regno == PT_SR)
90 return *(unsigned short *)addr;
91 }
84 return *addr; 92 return *addr;
85} 93}
86 94
@@ -98,6 +106,16 @@ static inline int put_reg(struct task_struct *task, int regno,
98 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); 106 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
99 else 107 else
100 return -1; 108 return -1;
109 /* Need to take stkadj into account. */
110 if (regno == PT_SR || regno == PT_PC) {
111 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
112 addr = (unsigned long *) ((unsigned long)addr + stkadj);
113 /* The sr is actually a 16 bit register. */
114 if (regno == PT_SR) {
115 *(unsigned short *)addr = data;
116 return 0;
117 }
118 }
101 *addr = data; 119 *addr = data;
102 return 0; 120 return 0;
103} 121}
@@ -107,7 +125,7 @@ static inline int put_reg(struct task_struct *task, int regno,
107 */ 125 */
108static inline void singlestep_disable(struct task_struct *child) 126static inline void singlestep_disable(struct task_struct *child)
109{ 127{
110 unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); 128 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
111 put_reg(child, PT_SR, tmp); 129 put_reg(child, PT_SR, tmp);
112 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); 130 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
113} 131}
@@ -122,15 +140,15 @@ void ptrace_disable(struct task_struct *child)
122 140
123void user_enable_single_step(struct task_struct *child) 141void user_enable_single_step(struct task_struct *child)
124{ 142{
125 unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); 143 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
126 put_reg(child, PT_SR, tmp | (T1_BIT << 16)); 144 put_reg(child, PT_SR, tmp | T1_BIT);
127 set_tsk_thread_flag(child, TIF_DELAYED_TRACE); 145 set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
128} 146}
129 147
130void user_enable_block_step(struct task_struct *child) 148void user_enable_block_step(struct task_struct *child)
131{ 149{
132 unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); 150 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
133 put_reg(child, PT_SR, tmp | (T0_BIT << 16)); 151 put_reg(child, PT_SR, tmp | T0_BIT);
134} 152}
135 153
136void user_disable_single_step(struct task_struct *child) 154void user_disable_single_step(struct task_struct *child)
@@ -152,8 +170,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
152 170
153 if (addr >= 0 && addr < 19) { 171 if (addr >= 0 && addr < 19) {
154 tmp = get_reg(child, addr); 172 tmp = get_reg(child, addr);
155 if (addr == PT_SR)
156 tmp >>= 16;
157 } else if (addr >= 21 && addr < 49) { 173 } else if (addr >= 21 && addr < 49) {
158 tmp = child->thread.fp[addr - 21]; 174 tmp = child->thread.fp[addr - 21];
159 /* Convert internal fpu reg representation 175 /* Convert internal fpu reg representation
@@ -163,7 +179,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
163 tmp = ((tmp & 0xffff0000) << 15) | 179 tmp = ((tmp & 0xffff0000) << 15) |
164 ((tmp & 0x0000ffff) << 16); 180 ((tmp & 0x0000ffff) << 16);
165 } else 181 } else
166 break; 182 goto out_eio;
167 ret = put_user(tmp, (unsigned long *)data); 183 ret = put_user(tmp, (unsigned long *)data);
168 break; 184 break;
169 185
@@ -174,9 +190,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
174 190
175 if (addr == PT_SR) { 191 if (addr == PT_SR) {
176 data &= SR_MASK; 192 data &= SR_MASK;
177 data <<= 16; 193 data |= get_reg(child, PT_SR) & ~SR_MASK;
178 data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); 194 }
179 } else if (addr >= 0 && addr < 19) { 195 if (addr >= 0 && addr < 19) {
180 if (put_reg(child, addr, data)) 196 if (put_reg(child, addr, data))
181 goto out_eio; 197 goto out_eio;
182 } else if (addr >= 21 && addr < 48) { 198 } else if (addr >= 21 && addr < 48) {
@@ -196,8 +212,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
196 case PTRACE_GETREGS: /* Get all gp regs from the child. */ 212 case PTRACE_GETREGS: /* Get all gp regs from the child. */
197 for (i = 0; i < 19; i++) { 213 for (i = 0; i < 19; i++) {
198 tmp = get_reg(child, i); 214 tmp = get_reg(child, i);
199 if (i == PT_SR)
200 tmp >>= 16;
201 ret = put_user(tmp, (unsigned long *)data); 215 ret = put_user(tmp, (unsigned long *)data);
202 if (ret) 216 if (ret)
203 break; 217 break;
@@ -212,8 +226,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
212 break; 226 break;
213 if (i == PT_SR) { 227 if (i == PT_SR) {
214 tmp &= SR_MASK; 228 tmp &= SR_MASK;
215 tmp <<= 16; 229 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
216 tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
217 } 230 }
218 put_reg(child, i, tmp); 231 put_reg(child, i, tmp);
219 data += sizeof(long); 232 data += sizeof(long);