aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2005-06-27 18:17:01 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-27 18:23:52 -0400
commit9ec4b1f356b3bad928ae8e2aa9caebfa737d52df (patch)
tree24d27ffed66595a9d864448ec53200ca1745f62c /arch/ppc64
parentd3b8a1a8496c83bc4a3cc76505c29255af15572c (diff)
[PATCH] kprobes: fix single-step out of line - take2
Now that PPC64 has no-execute support, here is a second try to fix the single step out of line during kprobe execution. Kprobes on x86_64 already solved this problem by allocating an executable page and using it as the scratch area for stepping out of line. Reuse that. Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc64')
-rw-r--r--arch/ppc64/kernel/kprobes.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index 782ce3efa2c1..86cc5496db9f 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -36,6 +36,8 @@
36#include <asm/kdebug.h> 36#include <asm/kdebug.h>
37#include <asm/sstep.h> 37#include <asm/sstep.h>
38 38
39static DECLARE_MUTEX(kprobe_mutex);
40
39static struct kprobe *current_kprobe; 41static struct kprobe *current_kprobe;
40static unsigned long kprobe_status, kprobe_saved_msr; 42static unsigned long kprobe_status, kprobe_saved_msr;
41static struct kprobe *kprobe_prev; 43static struct kprobe *kprobe_prev;
@@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p)
54 printk("Cannot register a kprobe on rfid or mtmsrd\n"); 56 printk("Cannot register a kprobe on rfid or mtmsrd\n");
55 ret = -EINVAL; 57 ret = -EINVAL;
56 } 58 }
59
60 /* insn must be on a special executable page on ppc64 */
61 if (!ret) {
62 up(&kprobe_mutex);
63 p->ainsn.insn = get_insn_slot();
64 down(&kprobe_mutex);
65 if (!p->ainsn.insn)
66 ret = -ENOMEM;
67 }
57 return ret; 68 return ret;
58} 69}
59 70
@@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p)
79 90
80void arch_remove_kprobe(struct kprobe *p) 91void arch_remove_kprobe(struct kprobe *p)
81{ 92{
93 up(&kprobe_mutex);
94 free_insn_slot(p->ainsn.insn);
95 down(&kprobe_mutex);
82} 96}
83 97
84static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 98static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
85{ 99{
100 kprobe_opcode_t insn = *p->ainsn.insn;
101
86 regs->msr |= MSR_SE; 102 regs->msr |= MSR_SE;
87 /*single step inline if it a breakpoint instruction*/ 103
88 if (p->opcode == BREAKPOINT_INSTRUCTION) 104 /* single step inline if it is a trap variant */
105 if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
89 regs->nip = (unsigned long)p->addr; 106 regs->nip = (unsigned long)p->addr;
90 else 107 else
91 regs->nip = (unsigned long)&p->ainsn.insn; 108 regs->nip = (unsigned long)p->ainsn.insn;
92} 109}
93 110
94static inline void save_previous_kprobe(void) 111static inline void save_previous_kprobe(void)
@@ -205,9 +222,10 @@ no_kprobe:
205static void resume_execution(struct kprobe *p, struct pt_regs *regs) 222static void resume_execution(struct kprobe *p, struct pt_regs *regs)
206{ 223{
207 int ret; 224 int ret;
225 unsigned int insn = *p->ainsn.insn;
208 226
209 regs->nip = (unsigned long)p->addr; 227 regs->nip = (unsigned long)p->addr;
210 ret = emulate_step(regs, p->ainsn.insn[0]); 228 ret = emulate_step(regs, insn);
211 if (ret == 0) 229 if (ret == 0)
212 regs->nip = (unsigned long)p->addr + 4; 230 regs->nip = (unsigned long)p->addr + 4;
213} 231}