diff options
author | Ananth N Mavinakayanahalli <ananth@in.ibm.com> | 2007-04-18 01:57:51 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-04-24 07:31:58 -0400 |
commit | e6349a958b3577da6e5c5eacda85c07f9a364cb5 (patch) | |
tree | 2d013d593c49ce13d9ce068dab70a876c3730de5 | |
parent | 6888199f7fe5ea496f48bb6de67b9b7f05b8071b (diff) |
[POWERPC] kprobes: Eliminate sstep exception if instruction can be emulated
For cases when probes are placed on instructions that can be emulated,
don't take the single-step exception.
Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/kprobes.c | 36 | ||||
-rw-r--r-- | include/asm-powerpc/kprobes.h | 5 |
2 files changed, 40 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index dd2886f97e98..ef647e7a9dc3 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
@@ -59,12 +59,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
59 | } | 59 | } |
60 | 60 | ||
61 | if (!ret) { | 61 | if (!ret) { |
62 | memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 62 | memcpy(p->ainsn.insn, p->addr, |
63 | MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | ||
63 | p->opcode = *p->addr; | 64 | p->opcode = *p->addr; |
64 | flush_icache_range((unsigned long)p->ainsn.insn, | 65 | flush_icache_range((unsigned long)p->ainsn.insn, |
65 | (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); | 66 | (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); |
66 | } | 67 | } |
67 | 68 | ||
69 | p->ainsn.boostable = 0; | ||
68 | return ret; | 70 | return ret; |
69 | } | 71 | } |
70 | 72 | ||
@@ -232,6 +234,38 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
232 | return 1; | 234 | return 1; |
233 | 235 | ||
234 | ss_probe: | 236 | ss_probe: |
237 | if (p->ainsn.boostable >= 0) { | ||
238 | unsigned int insn = *p->ainsn.insn; | ||
239 | |||
240 | /* regs->nip is also adjusted if emulate_step returns 1 */ | ||
241 | ret = emulate_step(regs, insn); | ||
242 | if (ret > 0) { | ||
243 | /* | ||
244 | * Once this instruction has been boosted | ||
245 | * successfully, set the boostable flag | ||
246 | */ | ||
247 | if (unlikely(p->ainsn.boostable == 0)) | ||
248 | p->ainsn.boostable = 1; | ||
249 | |||
250 | if (p->post_handler) | ||
251 | p->post_handler(p, regs, 0); | ||
252 | |||
253 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
254 | reset_current_kprobe(); | ||
255 | preempt_enable_no_resched(); | ||
256 | return 1; | ||
257 | } else if (ret < 0) { | ||
258 | /* | ||
259 | * We don't allow kprobes on mtmsr(d)/rfi(d), etc. | ||
260 | * So, we should never get here... but, its still | ||
261 | * good to catch them, just in case... | ||
262 | */ | ||
263 | printk("Can't step on instruction %x\n", insn); | ||
264 | BUG(); | ||
265 | } else if (ret == 0) | ||
266 | /* This instruction can't be boosted */ | ||
267 | p->ainsn.boostable = -1; | ||
268 | } | ||
235 | prepare_singlestep(p, regs); | 269 | prepare_singlestep(p, regs); |
236 | kcb->kprobe_status = KPROBE_HIT_SS; | 270 | kcb->kprobe_status = KPROBE_HIT_SS; |
237 | return 1; | 271 | return 1; |
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index 3a5dd492588f..f850ca7020ed 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h | |||
@@ -87,6 +87,11 @@ extern void arch_remove_kprobe(struct kprobe *p); | |||
87 | struct arch_specific_insn { | 87 | struct arch_specific_insn { |
88 | /* copy of original instruction */ | 88 | /* copy of original instruction */ |
89 | kprobe_opcode_t *insn; | 89 | kprobe_opcode_t *insn; |
90 | /* | ||
91 | * Set in kprobes code, initially to 0. If the instruction can be | ||
92 | * eumulated, this is set to 1, if not, to -1. | ||
93 | */ | ||
94 | int boostable; | ||
90 | }; | 95 | }; |
91 | 96 | ||
92 | struct prev_kprobe { | 97 | struct prev_kprobe { |