diff options
author | Ananth N Mavinakayanahalli <ananth@in.ibm.com> | 2005-06-27 18:17:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-27 18:23:52 -0400 |
commit | 9ec4b1f356b3bad928ae8e2aa9caebfa737d52df (patch) | |
tree | 24d27ffed66595a9d864448ec53200ca1745f62c /arch/ppc64 | |
parent | d3b8a1a8496c83bc4a3cc76505c29255af15572c (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.c | 26 |
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 | ||
39 | static DECLARE_MUTEX(kprobe_mutex); | ||
40 | |||
39 | static struct kprobe *current_kprobe; | 41 | static struct kprobe *current_kprobe; |
40 | static unsigned long kprobe_status, kprobe_saved_msr; | 42 | static unsigned long kprobe_status, kprobe_saved_msr; |
41 | static struct kprobe *kprobe_prev; | 43 | static 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 | ||
80 | void arch_remove_kprobe(struct kprobe *p) | 91 | void 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 | ||
84 | static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 98 | static 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 | ||
94 | static inline void save_previous_kprobe(void) | 111 | static inline void save_previous_kprobe(void) |
@@ -205,9 +222,10 @@ no_kprobe: | |||
205 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) | 222 | static 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 | } |