aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2009-05-28 17:26:38 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-08 23:29:25 -0400
commitec097c84dff17511f2693e6ef6c3064dfbf0a3af (patch)
tree3eac516a13730dcb371c094c0e8d35c9768c9c23 /arch
parentdac4ccfb64bcdd5b4c248ccc22903d67486573cd (diff)
powerpc: Add PTRACE_SINGLEBLOCK support
Reworked by: Benjamin Herrenschmidt <benh@kernel.crashing.org> This adds block-step support on powerpc, including a PTRACE_SINGLEBLOCK request for ptrace. The BookE implementation is tweaked to fire a single step after a block step in order to mimmic the server behaviour. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/ptrace.h4
-rw-r--r--arch/powerpc/kernel/head_booke.h10
-rw-r--r--arch/powerpc/kernel/ptrace.c23
-rw-r--r--arch/powerpc/kernel/traps.c34
4 files changed, 60 insertions, 11 deletions
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index c9c678fb2538..8c341490cfc5 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -135,7 +135,9 @@ do { \
135 * These are defined as per linux/ptrace.h, which see. 135 * These are defined as per linux/ptrace.h, which see.
136 */ 136 */
137#define arch_has_single_step() (1) 137#define arch_has_single_step() (1)
138#define arch_has_block_step() (!cpu_has_feature(CPU_FTR_601))
138extern void user_enable_single_step(struct task_struct *); 139extern void user_enable_single_step(struct task_struct *);
140extern void user_enable_block_step(struct task_struct *);
139extern void user_disable_single_step(struct task_struct *); 141extern void user_disable_single_step(struct task_struct *);
140 142
141#endif /* __ASSEMBLY__ */ 143#endif /* __ASSEMBLY__ */
@@ -288,4 +290,6 @@ extern void user_disable_single_step(struct task_struct *);
288#define PPC_PTRACE_PEEKUSR_3264 0x91 290#define PPC_PTRACE_PEEKUSR_3264 0x91
289#define PPC_PTRACE_POKEUSR_3264 0x90 291#define PPC_PTRACE_POKEUSR_3264 0x90
290 292
293#define PTRACE_SINGLEBLOCK 0x100 /* resume execution until next branch */
294
291#endif /* _ASM_POWERPC_PTRACE_H */ 295#endif /* _ASM_POWERPC_PTRACE_H */
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index 95f39f1e68d4..5f9febc8d143 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -256,7 +256,7 @@ label:
256 * off DE in the DSRR1 value and clearing the debug status. \ 256 * off DE in the DSRR1 value and clearing the debug status. \
257 */ \ 257 */ \
258 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ 258 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
259 andis. r10,r10,DBSR_IC@h; \ 259 andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \
260 beq+ 2f; \ 260 beq+ 2f; \
261 \ 261 \
262 lis r10,KERNELBASE@h; /* check if exception in vectors */ \ 262 lis r10,KERNELBASE@h; /* check if exception in vectors */ \
@@ -271,7 +271,7 @@ label:
271 \ 271 \
272 /* here it looks like we got an inappropriate debug exception. */ \ 272 /* here it looks like we got an inappropriate debug exception. */ \
2731: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \ 2731: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \
274 lis r10,DBSR_IC@h; /* clear the IC event */ \ 274 lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \
275 mtspr SPRN_DBSR,r10; \ 275 mtspr SPRN_DBSR,r10; \
276 /* restore state and get out */ \ 276 /* restore state and get out */ \
277 lwz r10,_CCR(r11); \ 277 lwz r10,_CCR(r11); \
@@ -309,7 +309,7 @@ label:
309 * off DE in the CSRR1 value and clearing the debug status. \ 309 * off DE in the CSRR1 value and clearing the debug status. \
310 */ \ 310 */ \
311 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ 311 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
312 andis. r10,r10,DBSR_IC@h; \ 312 andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \
313 beq+ 2f; \ 313 beq+ 2f; \
314 \ 314 \
315 lis r10,KERNELBASE@h; /* check if exception in vectors */ \ 315 lis r10,KERNELBASE@h; /* check if exception in vectors */ \
@@ -317,14 +317,14 @@ label:
317 cmplw r12,r10; \ 317 cmplw r12,r10; \
318 blt+ 2f; /* addr below exception vectors */ \ 318 blt+ 2f; /* addr below exception vectors */ \
319 \ 319 \
320 lis r10,DebugCrit@h; \ 320 lis r10,DebugCrit@h; \
321 ori r10,r10,DebugCrit@l; \ 321 ori r10,r10,DebugCrit@l; \
322 cmplw r12,r10; \ 322 cmplw r12,r10; \
323 bgt+ 2f; /* addr above exception vectors */ \ 323 bgt+ 2f; /* addr above exception vectors */ \
324 \ 324 \
325 /* here it looks like we got an inappropriate debug exception. */ \ 325 /* here it looks like we got an inappropriate debug exception. */ \
3261: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \ 3261: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \
327 lis r10,DBSR_IC@h; /* clear the IC event */ \ 327 lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \
328 mtspr SPRN_DBSR,r10; \ 328 mtspr SPRN_DBSR,r10; \
329 /* restore state and get out */ \ 329 /* restore state and get out */ \
330 lwz r10,_CCR(r11); \ 330 lwz r10,_CCR(r11); \
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 3635be61f899..9fa2c7dcd05a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -704,15 +704,34 @@ void user_enable_single_step(struct task_struct *task)
704 704
705 if (regs != NULL) { 705 if (regs != NULL) {
706#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) 706#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
707 task->thread.dbcr0 &= ~DBCR0_BT;
707 task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC; 708 task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
708 regs->msr |= MSR_DE; 709 regs->msr |= MSR_DE;
709#else 710#else
711 regs->msr &= ~MSR_BE;
710 regs->msr |= MSR_SE; 712 regs->msr |= MSR_SE;
711#endif 713#endif
712 } 714 }
713 set_tsk_thread_flag(task, TIF_SINGLESTEP); 715 set_tsk_thread_flag(task, TIF_SINGLESTEP);
714} 716}
715 717
718void user_enable_block_step(struct task_struct *task)
719{
720 struct pt_regs *regs = task->thread.regs;
721
722 if (regs != NULL) {
723#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
724 task->thread.dbcr0 &= ~DBCR0_IC;
725 task->thread.dbcr0 = DBCR0_IDM | DBCR0_BT;
726 regs->msr |= MSR_DE;
727#else
728 regs->msr &= ~MSR_SE;
729 regs->msr |= MSR_BE;
730#endif
731 }
732 set_tsk_thread_flag(task, TIF_SINGLESTEP);
733}
734
716void user_disable_single_step(struct task_struct *task) 735void user_disable_single_step(struct task_struct *task)
717{ 736{
718 struct pt_regs *regs = task->thread.regs; 737 struct pt_regs *regs = task->thread.regs;
@@ -726,10 +745,10 @@ void user_disable_single_step(struct task_struct *task)
726 745
727 if (regs != NULL) { 746 if (regs != NULL) {
728#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) 747#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
729 task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_IDM); 748 task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_BT | DBCR0_IDM);
730 regs->msr &= ~MSR_DE; 749 regs->msr &= ~MSR_DE;
731#else 750#else
732 regs->msr &= ~MSR_SE; 751 regs->msr &= ~(MSR_SE | MSR_BE);
733#endif 752#endif
734 } 753 }
735 clear_tsk_thread_flag(task, TIF_SINGLESTEP); 754 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 6a5b2b731f43..6f0ae1a9bfae 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1041,7 +1041,34 @@ void SoftwareEmulation(struct pt_regs *regs)
1041 1041
1042void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) 1042void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
1043{ 1043{
1044 if (debug_status & DBSR_IC) { /* instruction completion */ 1044 /* Hack alert: On BookE, Branch Taken stops on the branch itself, while
1045 * on server, it stops on the target of the branch. In order to simulate
1046 * the server behaviour, we thus restart right away with a single step
1047 * instead of stopping here when hitting a BT
1048 */
1049 if (debug_status & DBSR_BT) {
1050 regs->msr &= ~MSR_DE;
1051
1052 /* Disable BT */
1053 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_BT);
1054 /* Clear the BT event */
1055 mtspr(SPRN_DBSR, DBSR_BT);
1056
1057 /* Do the single step trick only when coming from userspace */
1058 if (user_mode(regs)) {
1059 current->thread.dbcr0 &= ~DBCR0_BT;
1060 current->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
1061 regs->msr |= MSR_DE;
1062 return;
1063 }
1064
1065 if (notify_die(DIE_SSTEP, "block_step", regs, 5,
1066 5, SIGTRAP) == NOTIFY_STOP) {
1067 return;
1068 }
1069 if (debugger_sstep(regs))
1070 return;
1071 } else if (debug_status & DBSR_IC) { /* Instruction complete */
1045 regs->msr &= ~MSR_DE; 1072 regs->msr &= ~MSR_DE;
1046 1073
1047 /* Disable instruction completion */ 1074 /* Disable instruction completion */
@@ -1057,9 +1084,8 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
1057 if (debugger_sstep(regs)) 1084 if (debugger_sstep(regs))
1058 return; 1085 return;
1059 1086
1060 if (user_mode(regs)) { 1087 if (user_mode(regs))
1061 current->thread.dbcr0 &= ~DBCR0_IC; 1088 current->thread.dbcr0 &= ~(DBCR0_IC);
1062 }
1063 1089
1064 _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); 1090 _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
1065 } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { 1091 } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {