aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-01-30 07:30:52 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:30:52 -0500
commit962ff3804d31a4d090bbcbd3d06a4b63e3a5b5fd (patch)
tree46e45a1076777b7454fd026f006f7517229b34b7 /arch
parente4aed6cc45f06acd35e3dfbbaf632c5d5aa897c0 (diff)
x86: x86-64 ptrace debugreg cleanup
This cleans up the 64-bit ptrace code to separate the guts of the debug register access from the implementation of PTRACE_PEEKUSR and PTRACE_POKEUSR. The new functions ptrace_[gs]et_debugreg are made global so that the ia32 code can later be changed to call them too. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/ptrace_64.c140
1 files changed, 66 insertions, 74 deletions
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index d0a0aeaaa0c2..4ba66d8af717 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -183,9 +183,63 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
183 183
184} 184}
185 185
186unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
187{
188 switch (n) {
189 case 0: return child->thread.debugreg0;
190 case 1: return child->thread.debugreg1;
191 case 2: return child->thread.debugreg2;
192 case 3: return child->thread.debugreg3;
193 case 6: return child->thread.debugreg6;
194 case 7: return child->thread.debugreg7;
195 }
196 return 0;
197}
198
199int ptrace_set_debugreg(struct task_struct *child, int n, unsigned long data)
200{
201 int i;
202
203 if (n < 4) {
204 int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
205 if (unlikely(data >= TASK_SIZE_OF(child) - dsize))
206 return -EIO;
207 }
208
209 switch (n) {
210 case 0: child->thread.debugreg0 = data; break;
211 case 1: child->thread.debugreg1 = data; break;
212 case 2: child->thread.debugreg2 = data; break;
213 case 3: child->thread.debugreg3 = data; break;
214
215 case 6:
216 if (data >> 32)
217 return -EIO;
218 child->thread.debugreg6 = data;
219 break;
220
221 case 7:
222 /*
223 * See ptrace_32.c for an explanation of this awkward check.
224 */
225 data &= ~DR_CONTROL_RESERVED;
226 for (i = 0; i < 4; i++)
227 if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
228 return -EIO;
229 child->thread.debugreg7 = data;
230 if (data)
231 set_tsk_thread_flag(child, TIF_DEBUG);
232 else
233 clear_tsk_thread_flag(child, TIF_DEBUG);
234 break;
235 }
236
237 return 0;
238}
239
186long arch_ptrace(struct task_struct *child, long request, long addr, long data) 240long arch_ptrace(struct task_struct *child, long request, long addr, long data)
187{ 241{
188 long i, ret; 242 long ret;
189 unsigned ui; 243 unsigned ui;
190 244
191 switch (request) { 245 switch (request) {
@@ -204,32 +258,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
204 addr > sizeof(struct user) - 7) 258 addr > sizeof(struct user) - 7)
205 break; 259 break;
206 260
207 switch (addr) { 261 tmp = 0;
208 case 0 ... sizeof(struct user_regs_struct) - sizeof(long): 262 if (addr < sizeof(struct user_regs_struct))
209 tmp = getreg(child, addr); 263 tmp = getreg(child, addr);
210 break; 264 else if (addr >= offsetof(struct user, u_debugreg[0])) {
211 case offsetof(struct user, u_debugreg[0]): 265 addr -= offsetof(struct user, u_debugreg[0]);
212 tmp = child->thread.debugreg0; 266 tmp = ptrace_get_debugreg(child, addr / sizeof(long));
213 break;
214 case offsetof(struct user, u_debugreg[1]):
215 tmp = child->thread.debugreg1;
216 break;
217 case offsetof(struct user, u_debugreg[2]):
218 tmp = child->thread.debugreg2;
219 break;
220 case offsetof(struct user, u_debugreg[3]):
221 tmp = child->thread.debugreg3;
222 break;
223 case offsetof(struct user, u_debugreg[6]):
224 tmp = child->thread.debugreg6;
225 break;
226 case offsetof(struct user, u_debugreg[7]):
227 tmp = child->thread.debugreg7;
228 break;
229 default:
230 tmp = 0;
231 break;
232 } 267 }
268
233 ret = put_user(tmp,(unsigned long __user *) data); 269 ret = put_user(tmp,(unsigned long __user *) data);
234 break; 270 break;
235 } 271 }
@@ -241,63 +277,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
241 break; 277 break;
242 278
243 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 279 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
244 {
245 int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
246 ret = -EIO; 280 ret = -EIO;
247 if ((addr & 7) || 281 if ((addr & 7) ||
248 addr > sizeof(struct user) - 7) 282 addr > sizeof(struct user) - 7)
249 break; 283 break;
250 284
251 switch (addr) { 285 if (addr < sizeof(struct user_regs_struct))
252 case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
253 ret = putreg(child, addr, data); 286 ret = putreg(child, addr, data);
254 break; 287 else if (addr >= offsetof(struct user, u_debugreg[0])) {
255 /* Disallows to set a breakpoint into the vsyscall */ 288 addr -= offsetof(struct user, u_debugreg[0]);
256 case offsetof(struct user, u_debugreg[0]): 289 ret = ptrace_set_debugreg(child,
257 if (data >= TASK_SIZE_OF(child) - dsize) break; 290 addr / sizeof(long), data);
258 child->thread.debugreg0 = data;
259 ret = 0;
260 break;
261 case offsetof(struct user, u_debugreg[1]):
262 if (data >= TASK_SIZE_OF(child) - dsize) break;
263 child->thread.debugreg1 = data;
264 ret = 0;
265 break;
266 case offsetof(struct user, u_debugreg[2]):
267 if (data >= TASK_SIZE_OF(child) - dsize) break;
268 child->thread.debugreg2 = data;
269 ret = 0;
270 break;
271 case offsetof(struct user, u_debugreg[3]):
272 if (data >= TASK_SIZE_OF(child) - dsize) break;
273 child->thread.debugreg3 = data;
274 ret = 0;
275 break;
276 case offsetof(struct user, u_debugreg[6]):
277 if (data >> 32)
278 break;
279 child->thread.debugreg6 = data;
280 ret = 0;
281 break;
282 case offsetof(struct user, u_debugreg[7]):
283 /* See arch/i386/kernel/ptrace.c for an explanation of
284 * this awkward check.*/
285 data &= ~DR_CONTROL_RESERVED;
286 for(i=0; i<4; i++)
287 if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
288 break;
289 if (i == 4) {
290 child->thread.debugreg7 = data;
291 if (data)
292 set_tsk_thread_flag(child, TIF_DEBUG);
293 else
294 clear_tsk_thread_flag(child, TIF_DEBUG);
295 ret = 0;
296 }
297 break;
298 } 291 }
299 break; 292 break;
300 }
301 293
302#ifdef CONFIG_IA32_EMULATION 294#ifdef CONFIG_IA32_EMULATION
303 /* This makes only sense with 32bit programs. Allow a 295 /* This makes only sense with 32bit programs. Allow a