Skip to contentSkip to conversation

kprobes: fix single-step out of line - take2

PATCH New Ananth N Mavinakayanahalli 1 participant 1 message Jun 17, 2005 kprobes

lore
Share & tools
lore
#0 lore raw

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
Index: linux-2.6.12-rc6/arch/ppc64/kernel/kprobes.c
===================================================================
@@ -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 *p
 		printk("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(struct 
 
 static 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
Index: linux-2.6.12-rc6/include/linux/kprobes.h
===================================================================
@@ -101,6 +101,8 @@ extern int arch_prepare_kprobe(struct kp
 extern 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
Index: linux-2.6.12-rc6/include/asm-ppc64/kprobes.h
===================================================================
@@ -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