diff options
| author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-11-09 15:03:43 -0500 |
|---|---|---|
| committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-11-10 05:23:05 -0500 |
| commit | 9f6b3c2c30cfbb1166ce7e74a8f9fd93ae19d2de (patch) | |
| tree | 1144b1c516327765c7daacc6f4b23cc606a0c013 | |
| parent | 676c0dbe6e514fdd8e434a9e623c781aa9b40b15 (diff) | |
hw-breakpoints: Fix broken a.out format dump
Fix the broken a.out format dump. For now we only dump the ptrace
breakpoints.
TODO: Dump every perf breakpoints for the current thread, not only
ptrace based ones.
Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: "K. Prasad" <prasad@linux.vnet.ibm.com>
| -rw-r--r-- | arch/x86/include/asm/a.out-core.h | 10 | ||||
| -rw-r--r-- | arch/x86/include/asm/debugreg.h | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/hw_breakpoint.c | 35 |
3 files changed, 39 insertions, 8 deletions
diff --git a/arch/x86/include/asm/a.out-core.h b/arch/x86/include/asm/a.out-core.h index fc4685dd6e4d..7a15588e45d4 100644 --- a/arch/x86/include/asm/a.out-core.h +++ b/arch/x86/include/asm/a.out-core.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <linux/user.h> | 18 | #include <linux/user.h> |
| 19 | #include <linux/elfcore.h> | 19 | #include <linux/elfcore.h> |
| 20 | #include <asm/debugreg.h> | ||
| 20 | 21 | ||
| 21 | /* | 22 | /* |
| 22 | * fill in the user structure for an a.out core dump | 23 | * fill in the user structure for an a.out core dump |
| @@ -32,14 +33,7 @@ static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump) | |||
| 32 | >> PAGE_SHIFT; | 33 | >> PAGE_SHIFT; |
| 33 | dump->u_dsize -= dump->u_tsize; | 34 | dump->u_dsize -= dump->u_tsize; |
| 34 | dump->u_ssize = 0; | 35 | dump->u_ssize = 0; |
| 35 | dump->u_debugreg[0] = current->thread.debugreg[0]; | 36 | aout_dump_debugregs(dump); |
| 36 | dump->u_debugreg[1] = current->thread.debugreg[1]; | ||
| 37 | dump->u_debugreg[2] = current->thread.debugreg[2]; | ||
| 38 | dump->u_debugreg[3] = current->thread.debugreg[3]; | ||
| 39 | dump->u_debugreg[4] = 0; | ||
| 40 | dump->u_debugreg[5] = 0; | ||
| 41 | dump->u_debugreg[6] = current->thread.debugreg6; | ||
| 42 | dump->u_debugreg[7] = current->thread.debugreg7; | ||
| 43 | 37 | ||
| 44 | if (dump->start_stack < TASK_SIZE) | 38 | if (dump->start_stack < TASK_SIZE) |
| 45 | dump->u_ssize = ((unsigned long)(TASK_SIZE - dump->start_stack)) | 39 | dump->u_ssize = ((unsigned long)(TASK_SIZE - dump->start_stack)) |
diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 9a3333c91f9a..f1b673f08239 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h | |||
| @@ -89,6 +89,8 @@ static inline void hw_breakpoint_disable(void) | |||
| 89 | set_debugreg(0UL, 3); | 89 | set_debugreg(0UL, 3); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | extern void aout_dump_debugregs(struct user *dump); | ||
| 93 | |||
| 92 | #ifdef CONFIG_KVM | 94 | #ifdef CONFIG_KVM |
| 93 | extern void hw_breakpoint_restore(void); | 95 | extern void hw_breakpoint_restore(void); |
| 94 | #endif | 96 | #endif |
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index e622620790bd..57dcee5fa958 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c | |||
| @@ -376,6 +376,41 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | /* | 378 | /* |
| 379 | * Dump the debug register contents to the user. | ||
| 380 | * We can't dump our per cpu values because it | ||
| 381 | * may contain cpu wide breakpoint, something that | ||
| 382 | * doesn't belong to the current task. | ||
| 383 | * | ||
| 384 | * TODO: include non-ptrace user breakpoints (perf) | ||
| 385 | */ | ||
| 386 | void aout_dump_debugregs(struct user *dump) | ||
| 387 | { | ||
| 388 | int i; | ||
| 389 | int dr7 = 0; | ||
| 390 | struct perf_event *bp; | ||
| 391 | struct arch_hw_breakpoint *info; | ||
| 392 | struct thread_struct *thread = ¤t->thread; | ||
| 393 | |||
| 394 | for (i = 0; i < HBP_NUM; i++) { | ||
| 395 | bp = thread->ptrace_bps[i]; | ||
| 396 | |||
| 397 | if (bp && !bp->attr.disabled) { | ||
| 398 | dump->u_debugreg[i] = bp->attr.bp_addr; | ||
| 399 | info = counter_arch_bp(bp); | ||
| 400 | dr7 |= encode_dr7(i, info->len, info->type); | ||
| 401 | } else { | ||
| 402 | dump->u_debugreg[i] = 0; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | dump->u_debugreg[4] = 0; | ||
| 407 | dump->u_debugreg[5] = 0; | ||
| 408 | dump->u_debugreg[6] = current->thread.debugreg6; | ||
| 409 | |||
| 410 | dump->u_debugreg[7] = dr7; | ||
| 411 | } | ||
| 412 | |||
| 413 | /* | ||
| 379 | * Release the user breakpoints used by ptrace | 414 | * Release the user breakpoints used by ptrace |
| 380 | */ | 415 | */ |
| 381 | void flush_ptrace_hw_breakpoint(struct task_struct *tsk) | 416 | void flush_ptrace_hw_breakpoint(struct task_struct *tsk) |
