diff options
author | Roland McGrath <roland@redhat.com> | 2009-05-28 21:26:38 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-09 13:29:25 +1000 |
commit | ec097c84dff17511f2693e6ef6c3064dfbf0a3af (patch) | |
tree | 3eac516a13730dcb371c094c0e8d35c9768c9c23 /arch/powerpc/kernel/traps.c | |
parent | dac4ccfb64bcdd5b4c248ccc22903d67486573cd (diff) | |
download | op-kernel-dev-ec097c84dff17511f2693e6ef6c3064dfbf0a3af.zip op-kernel-dev-ec097c84dff17511f2693e6ef6c3064dfbf0a3af.tar.gz |
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 6a5b2b7..6f0ae1a 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1041,7 +1041,34 @@ void SoftwareEmulation(struct pt_regs *regs) void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) { - if (debug_status & DBSR_IC) { /* instruction completion */ + /* Hack alert: On BookE, Branch Taken stops on the branch itself, while + * on server, it stops on the target of the branch. In order to simulate + * the server behaviour, we thus restart right away with a single step + * instead of stopping here when hitting a BT + */ + if (debug_status & DBSR_BT) { + regs->msr &= ~MSR_DE; + + /* Disable BT */ + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_BT); + /* Clear the BT event */ + mtspr(SPRN_DBSR, DBSR_BT); + + /* Do the single step trick only when coming from userspace */ + if (user_mode(regs)) { + current->thread.dbcr0 &= ~DBCR0_BT; + current->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC; + regs->msr |= MSR_DE; + return; + } + + if (notify_die(DIE_SSTEP, "block_step", regs, 5, + 5, SIGTRAP) == NOTIFY_STOP) { + return; + } + if (debugger_sstep(regs)) + return; + } else if (debug_status & DBSR_IC) { /* Instruction complete */ regs->msr &= ~MSR_DE; /* Disable instruction completion */ @@ -1057,9 +1084,8 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) if (debugger_sstep(regs)) return; - if (user_mode(regs)) { - current->thread.dbcr0 &= ~DBCR0_IC; - } + if (user_mode(regs)) + current->thread.dbcr0 &= ~(DBCR0_IC); _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { |