kprobes: fix single-step out of line - take2
PATCH 1/1 kprobes: fix single-step out of line - take2
Hi,
Here is the second try to fix the single-step out of line issues for PPC64 now that the kernel has no-execute support.
x86_64 also has no-execute support and kprobes on x86_64 solved this issue by allocating an executable kernel page and using it as a scratch area for instructions to be stepped out of line. Reuse that for PPC64 too.
Thanks,
Ananth
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.
Patch against 2.6.12-rc6-git8
arch/ppc64/kernel/kprobes.c | 26 ++++++++- arch/x86_64/kernel/kprobes.c | 112 ------------------------------------------- include/asm-ppc64/kprobes.h | 2 include/linux/kprobes.h | 2 kernel/kprobes.c | 101 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 117 deletions(-)
arch/ppc64/kernel/kprobes.c +22 -4
@@ -39,6 +39,8 @@#define KPROBE_HIT_ACTIVE 0x00000001#define KPROBE_HIT_SS 0x00000002 +static DECLARE_MUTEX (kprobe_mutex); +static struct kprobe *current_kprobe;static unsigned long kprobe_status, kprobe_saved_msr;static struct pt_regs jprobe_saved_regs;
@@ -55,6 +57,15 @@ int arch_prepare_kprobe(struct kprobe *pprintk ("Cannot register a kprobe on rfid or mtmsrd\n" ); ret = -EINVAL ; } + +/* insn must be on a special executable page on ppc64 */ +if (!ret) { +up (&kprobe_mutex); + p->ainsn.insn =get_insn_slot (); +down (&kprobe_mutex); +if (!p->ainsn.insn) + ret = -ENOMEM ; + }return ret; }
@@ -65,6 +76,9 @@ void arch_copy_kprobe(struct kprobe *p)void arch_remove_kprobe (struct kprobe *p) { +up (&kprobe_mutex); +free_insn_slot (p->ainsn.insn); +down (&kprobe_mutex); }static inline void disarm_kprobe (struct kprobe *p,struct pt_regs *regs)
@@ -75,12 +89,15 @@ static inline void disarm_kprobe(structstatic inline void prepare_singlestep (struct kprobe *p,struct pt_regs *regs) { +kprobe_opcode_t insn = *p->ainsn.insn; + regs->msr |=MSR_SE ; -/*single step inline if it a breakpoint instruction*/ -if (p->opcode ==BREAKPOINT_INSTRUCTION ) + +/* single step inline if it is a trap variant */ +if (IS_TW (insn) ||IS_TD (insn) ||IS_TWI (insn) ||IS_TDI (insn)) regs->nip = (unsigned long )p->addr;else - regs->nip = (unsigned long )&p->ainsn.insn; + regs->nip = (unsigned long )p->ainsn.insn; }static inline int kprobe_handler (struct pt_regs *regs)
@@ -172,9 +189,10 @@ no_kprobe:static void resume_execution (struct kprobe *p,struct pt_regs *regs) {int ret; +unsigned int insn = *p->ainsn.insn; regs->nip = (unsigned long )p->addr; - ret =emulate_step (regs, p->ainsn.insn[0 ]); + ret =emulate_step (regs, insn);if (ret ==0 ) regs->nip = (unsigned long )p->addr +4 ; }
arch/x86_64/kernel/kprobes.c +0 -112
127 lines not on this page · raw message
include/linux/kprobes.h +2 -0
@@ -101,6 +101,8 @@ extern int arch_prepare_kprobe(struct kpextern void arch_copy_kprobe (struct kprobe *p);extern void arch_remove_kprobe (struct kprobe *p);extern void show_registers (struct pt_regs *regs); +extern kprobe_opcode_t *get_insn_slot (void ); +extern void free_insn_slot (kprobe_opcode_t *slot);/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ struct kprobe *get_kprobe (void *addr);
kernel/kprobes.c +101 -0
113 lines not on this page · raw message
include/asm-ppc64/kprobes.h +1 -1
@@ -45,7 +45,7 @@ typedef unsigned int kprobe_opcode_t;/* Architecture specific copy of original instruction */ struct arch_specific_insn {/* copy of original instruction */ -kprobe_opcode_t insn[MAX_INSN_SIZE ]; +kprobe_opcode_t *insn; };#ifdef CONFIG_KPROBES