diff options
author | Roland McGrath <roland@redhat.com> | 2009-05-28 17:26:38 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-08 23:29:25 -0400 |
commit | ec097c84dff17511f2693e6ef6c3064dfbf0a3af (patch) | |
tree | 3eac516a13730dcb371c094c0e8d35c9768c9c23 /arch/powerpc/kernel/traps.c | |
parent | dac4ccfb64bcdd5b4c248ccc22903d67486573cd (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/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 34 |
1 files changed, 30 insertions, 4 deletions
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 | ||
1042 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | 1042 | void __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)) { |