All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] parisc: Avoid using hardware single-step in kprobes
@ 2021-11-09 21:25 Helge Deller
  0 siblings, 0 replies; only message in thread
From: Helge Deller @ 2021-11-09 21:25 UTC (permalink / raw)
  To: linux-parisc, James Bottomley, John David Anglin, Sven Schnelle

This patch changes the kprobe and kretprobe feature to use another
break instruction instead of relying on the hardware single-step
feature.
That way those kprobes now work in qemu as well, because in qemu we
don't emulate yet single-stepping.

Signed-off-by: Helge Deller <deller@gmx.de>

diff --git a/arch/parisc/include/asm/kprobes.h b/arch/parisc/include/asm/kprobes.h
index 904034da4974..0a175ac87698 100644
--- a/arch/parisc/include/asm/kprobes.h
+++ b/arch/parisc/include/asm/kprobes.h
@@ -18,8 +18,9 @@
 #include <linux/notifier.h>

 #define PARISC_KPROBES_BREAK_INSN	0x3ff801f
+#define PARISC_KPROBES_BREAK_INSN2	0x3ff801e
 #define  __ARCH_WANT_KPROBES_INSN_SLOT
-#define MAX_INSN_SIZE 1
+#define MAX_INSN_SIZE 2

 typedef u32 kprobe_opcode_t;
 struct kprobe;
@@ -29,7 +30,7 @@ void arch_remove_kprobe(struct kprobe *p);
 #define flush_insn_slot(p) \
 	flush_icache_range((unsigned long)&(p)->ainsn.insn[0], \
 			   (unsigned long)&(p)->ainsn.insn[0] + \
-			   sizeof(kprobe_opcode_t))
+			   MAX_INSN_SIZE*sizeof(kprobe_opcode_t))

 #define kretprobe_blacklist_size    0

diff --git a/arch/parisc/kernel/kprobes.c b/arch/parisc/kernel/kprobes.c
index e2bdb5a5f93e..2ca34fc250a6 100644
--- a/arch/parisc/kernel/kprobes.c
+++ b/arch/parisc/kernel/kprobes.c
@@ -5,6 +5,7 @@
  * PA-RISC kprobes implementation
  *
  * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ * Copyright (c) 2021 Helge Deller <deller@gmx.de>
  */

 #include <linux/types.h>
@@ -25,9 +26,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
 	if (!p->ainsn.insn)
 		return -ENOMEM;

-	memcpy(p->ainsn.insn, p->addr,
-		MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+	/*
+	 * Set up new instructions. Second break instruction will
+	 * trigger call of parisc_kprobe_ss_handler().
+	 */
 	p->opcode = *p->addr;
+	p->ainsn.insn[0] = p->opcode;
+	p->ainsn.insn[1] = PARISC_KPROBES_BREAK_INSN2;
+
 	flush_insn_slot(p);
 	return 0;
 }
@@ -73,9 +79,7 @@ static void __kprobes setup_singlestep(struct kprobe *p,
 {
 	kcb->iaoq[0] = regs->iaoq[0];
 	kcb->iaoq[1] = regs->iaoq[1];
-	regs->iaoq[0] = (unsigned long)p->ainsn.insn;
-	mtctl(0, 0);
-	regs->gr[0] |= PSW_R;
+	instruction_pointer_set(regs, (unsigned long)p->ainsn.insn);
 }

 int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs)
@@ -165,9 +170,8 @@ int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
 		regs->iaoq[0] = kcb->iaoq[1];
 		break;
 	default:
-		regs->iaoq[1] = kcb->iaoq[0];
-		regs->iaoq[1] += (regs->iaoq[1] - regs->iaoq[0]) + 4;
 		regs->iaoq[0] = kcb->iaoq[1];
+		regs->iaoq[1] = regs->iaoq[0] + 4;
 		break;
 	}
 	kcb->kprobe_status = KPROBE_HIT_SSDONE;
@@ -191,14 +195,17 @@ static struct kprobe trampoline_p = {
 static int __kprobes trampoline_probe_handler(struct kprobe *p,
 					      struct pt_regs *regs)
 {
-	unsigned long orig_ret_address;
-
-	orig_ret_address = __kretprobe_trampoline_handler(regs, NULL);
-	instruction_pointer_set(regs, orig_ret_address);
+	__kretprobe_trampoline_handler(regs, NULL);

 	return 1;
 }

+void arch_kretprobe_fixup_return(struct pt_regs *regs,
+				 kprobe_opcode_t *correct_ret_addr)
+{
+	regs->gr[2] = (unsigned long)correct_ret_addr;
+}
+
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 				      struct pt_regs *regs)
 {
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index b11fb26ce299..3ec3be8e90c5 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -302,7 +302,10 @@ static void handle_break(struct pt_regs *regs)
 		parisc_kprobe_break_handler(regs);
 		return;
 	}
-
+	if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2)) {
+		parisc_kprobe_ss_handler(regs);
+		return;
+	}
 #endif

 #ifdef CONFIG_KGDB
@@ -539,11 +542,6 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
 		/* Recovery counter trap */
 		regs->gr[0] &= ~PSW_R;

-#ifdef CONFIG_KPROBES
-		if (parisc_kprobe_ss_handler(regs))
-			return;
-#endif
-
 #ifdef CONFIG_KGDB
 		if (kgdb_single_step) {
 			kgdb_handle_exception(0, SIGTRAP, 0, regs);

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2021-11-09 21:25 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-09 21:25 [PATCH] parisc: Avoid using hardware single-step in kprobes Helge Deller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.