mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Add uprobes support for LoongArch
@ 2023-04-19  9:56 Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 1/6] LoongArch: Move three functions from kprobes.c to inst.c Tiezhu Yang
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:56 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

v3:
  -- Check atomic instructions in insns_not_supported()
  -- Remove five DIE_* definitions in kdebug.h

v2:
  -- Move the functions to inst.c in patch #1
  -- Pass around union for insns_not_supported(),
     insns_need_simulation() and arch_simulate_insn()

v1:
  -- Split the RFC patch #2 into two patches
  -- Use larch_insn_gen_break() to generate break insns
     for kprobes and uprobes
  -- Pass around instruction word instead of union for
     insns_not_supported(), insns_need_simulation() and
     arch_simulate_insn() to avoid type conversion for callers
  -- Add a simple test case for uprobes in the commit message

Tiezhu Yang (6):
  LoongArch: Move three functions from kprobes.c to inst.c
  LoongArch: Add larch_insn_gen_break() to generate break insns
  LoongArch: Use larch_insn_gen_break() for kprobes
  LoongArch: Add uprobes support
  LoongArch: Check atomic instructions in insns_not_supported()
  LoongArch: Remove five DIE_* definitions in kdebug.h

 arch/loongarch/Kconfig               |   3 +
 arch/loongarch/include/asm/inst.h    |  42 ++++++++++
 arch/loongarch/include/asm/kdebug.h  |   5 --
 arch/loongarch/include/asm/kprobes.h |   2 +-
 arch/loongarch/include/asm/uprobes.h |  36 +++++++++
 arch/loongarch/kernel/Makefile       |   1 +
 arch/loongarch/kernel/inst.c         |  54 +++++++++++++
 arch/loongarch/kernel/kprobes.c      |  75 ++++--------------
 arch/loongarch/kernel/traps.c        |   9 +--
 arch/loongarch/kernel/uprobes.c      | 143 +++++++++++++++++++++++++++++++++++
 10 files changed, 298 insertions(+), 72 deletions(-)
 create mode 100644 arch/loongarch/include/asm/uprobes.h
 create mode 100644 arch/loongarch/kernel/uprobes.c

-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 1/6] LoongArch: Move three functions from kprobes.c to inst.c
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
@ 2023-04-19  9:56 ` Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 2/6] LoongArch: Add larch_insn_gen_break() to generate break insns Tiezhu Yang
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:56 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

The functions insns_not_supported(), insns_need_simulation()
and arch_simulate_insn() will be used for uprobes, move them
from kprobes.c to inst.c, this is preparation for later patch,
no functionality change.

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/include/asm/inst.h |  4 ++++
 arch/loongarch/kernel/inst.c      | 39 +++++++++++++++++++++++++++++++++
 arch/loongarch/kernel/kprobes.c   | 46 ++-------------------------------------
 3 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index a04fe75..9ea485b 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -409,6 +409,10 @@ static inline bool is_self_loop_ins(union loongarch_instruction *ip, struct pt_r
 void simu_pc(struct pt_regs *regs, union loongarch_instruction insn);
 void simu_branch(struct pt_regs *regs, union loongarch_instruction insn);
 
+bool insns_not_supported(union loongarch_instruction insn);
+bool insns_need_simulation(union loongarch_instruction insn);
+void arch_simulate_insn(union loongarch_instruction insn, struct pt_regs *regs);
+
 int larch_insn_read(void *addr, u32 *insnp);
 int larch_insn_write(void *addr, u32 insn);
 int larch_insn_patch_text(void *addr, u32 insn);
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index 258ef26..6f61956 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -133,6 +133,45 @@ void simu_branch(struct pt_regs *regs, union loongarch_instruction insn)
 	}
 }
 
+bool insns_not_supported(union loongarch_instruction insn)
+{
+	switch (insn.reg2i14_format.opcode) {
+	case llw_op:
+	case lld_op:
+	case scw_op:
+	case scd_op:
+		pr_notice("ll and sc instructions are not supported\n");
+		return true;
+	}
+
+	switch (insn.reg1i21_format.opcode) {
+	case bceqz_op:
+		pr_notice("bceqz and bcnez instructions are not supported\n");
+		return true;
+	}
+
+	return false;
+}
+
+bool insns_need_simulation(union loongarch_instruction insn)
+{
+	if (is_pc_ins(&insn))
+		return true;
+
+	if (is_branch_ins(&insn))
+		return true;
+
+	return false;
+}
+
+void arch_simulate_insn(union loongarch_instruction insn, struct pt_regs *regs)
+{
+	if (is_pc_ins(&insn))
+		simu_pc(regs, insn);
+	else if (is_branch_ins(&insn))
+		simu_branch(regs, insn);
+}
+
 int larch_insn_read(void *addr, u32 *insnp)
 {
 	int ret;
diff --git a/arch/loongarch/kernel/kprobes.c b/arch/loongarch/kernel/kprobes.c
index 56c8c4b..08c78d2 100644
--- a/arch/loongarch/kernel/kprobes.c
+++ b/arch/loongarch/kernel/kprobes.c
@@ -21,48 +21,6 @@ static const union loongarch_instruction singlestep_insn = {
 DEFINE_PER_CPU(struct kprobe *, current_kprobe);
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
-static bool insns_not_supported(union loongarch_instruction insn)
-{
-	switch (insn.reg2i14_format.opcode) {
-	case llw_op:
-	case lld_op:
-	case scw_op:
-	case scd_op:
-		pr_notice("kprobe: ll and sc instructions are not supported\n");
-		return true;
-	}
-
-	switch (insn.reg1i21_format.opcode) {
-	case bceqz_op:
-		pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
-		return true;
-	}
-
-	return false;
-}
-NOKPROBE_SYMBOL(insns_not_supported);
-
-static bool insns_need_simulation(struct kprobe *p)
-{
-	if (is_pc_ins(&p->opcode))
-		return true;
-
-	if (is_branch_ins(&p->opcode))
-		return true;
-
-	return false;
-}
-NOKPROBE_SYMBOL(insns_need_simulation);
-
-static void arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
-{
-	if (is_pc_ins(&p->opcode))
-		simu_pc(regs, p->opcode);
-	else if (is_branch_ins(&p->opcode))
-		simu_branch(regs, p->opcode);
-}
-NOKPROBE_SYMBOL(arch_simulate_insn);
-
 static void arch_prepare_ss_slot(struct kprobe *p)
 {
 	p->ainsn.insn[0] = *p->addr;
@@ -89,7 +47,7 @@ int arch_prepare_kprobe(struct kprobe *p)
 	if (insns_not_supported(p->opcode))
 		return -EINVAL;
 
-	if (insns_need_simulation(p)) {
+	if (insns_need_simulation(p->opcode)) {
 		p->ainsn.insn = NULL;
 	} else {
 		p->ainsn.insn = get_insn_slot();
@@ -220,7 +178,7 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
 		regs->csr_era = (unsigned long)p->ainsn.insn;
 	} else {
 		/* simulate single steping */
-		arch_simulate_insn(p, regs);
+		arch_simulate_insn(p->opcode, regs);
 		/* now go for post processing */
 		post_kprobe_handler(p, kcb, regs);
 	}
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 2/6] LoongArch: Add larch_insn_gen_break() to generate break insns
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 1/6] LoongArch: Move three functions from kprobes.c to inst.c Tiezhu Yang
@ 2023-04-19  9:56 ` Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 3/6] LoongArch: Use larch_insn_gen_break() for kprobes Tiezhu Yang
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:56 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

There exist various break insns such as BRK_KPROBE_BP, BRK_KPROBE_SSTEPBP,
BRK_UPROBE_BP and BRK_UPROBE_XOLBP, add larch_insn_gen_break() to generate
break insns simpler, this is preparation for later patch.

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/include/asm/inst.h | 12 ++++++++++++
 arch/loongarch/kernel/inst.c      |  9 +++++++++
 2 files changed, 21 insertions(+)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 9ea485b..061c0ea 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -421,6 +421,8 @@ u32 larch_insn_gen_nop(void);
 u32 larch_insn_gen_b(unsigned long pc, unsigned long dest);
 u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest);
 
+u32 larch_insn_gen_break(int imm);
+
 u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk);
 u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj);
 
@@ -439,6 +441,16 @@ static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
 	return val < (1UL << bit);
 }
 
+#define DEF_EMIT_REG0I15_FORMAT(NAME, OP)				\
+static inline void emit_##NAME(union loongarch_instruction *insn,	\
+			       int imm)					\
+{									\
+	insn->reg0i15_format.opcode = OP;				\
+	insn->reg0i15_format.immediate = imm;				\
+}
+
+DEF_EMIT_REG0I15_FORMAT(break, break_op)
+
 #define DEF_EMIT_REG0I26_FORMAT(NAME, OP)				\
 static inline void emit_##NAME(union loongarch_instruction *insn,	\
 			       int offset)				\
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index 6f61956..1d7d579 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -247,6 +247,15 @@ u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
 	return insn.word;
 }
 
+u32 larch_insn_gen_break(int imm)
+{
+	union loongarch_instruction insn;
+
+	emit_break(&insn, imm);
+
+	return insn.word;
+}
+
 u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk)
 {
 	union loongarch_instruction insn;
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 3/6] LoongArch: Use larch_insn_gen_break() for kprobes
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 1/6] LoongArch: Move three functions from kprobes.c to inst.c Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 2/6] LoongArch: Add larch_insn_gen_break() to generate break insns Tiezhu Yang
@ 2023-04-19  9:56 ` Tiezhu Yang
  2023-04-19  9:56 ` [PATCH v3 4/6] LoongArch: Add uprobes support Tiezhu Yang
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:56 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

For now, we can use larch_insn_gen_break() to define KPROBE_BP_INSN and
KPROBE_SSTEPBP_INSN. Because larch_insn_gen_break() returns instruction
word, define kprobe_opcode_t as u32, then do some small changes related
with type conversion, no functional change intended.

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/include/asm/kprobes.h |  2 +-
 arch/loongarch/kernel/kprobes.c      | 33 ++++++++++++++-------------------
 2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/arch/loongarch/include/asm/kprobes.h b/arch/loongarch/include/asm/kprobes.h
index 798020a..7ef7a0f 100644
--- a/arch/loongarch/include/asm/kprobes.h
+++ b/arch/loongarch/include/asm/kprobes.h
@@ -22,7 +22,7 @@ do {									\
 
 #define kretprobe_blacklist_size	0
 
-typedef union loongarch_instruction kprobe_opcode_t;
+typedef u32 kprobe_opcode_t;
 
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
diff --git a/arch/loongarch/kernel/kprobes.c b/arch/loongarch/kernel/kprobes.c
index 08c78d2..1835102 100644
--- a/arch/loongarch/kernel/kprobes.c
+++ b/arch/loongarch/kernel/kprobes.c
@@ -4,19 +4,8 @@
 #include <linux/preempt.h>
 #include <asm/break.h>
 
-static const union loongarch_instruction breakpoint_insn = {
-	.reg0i15_format = {
-		.opcode = break_op,
-		.immediate = BRK_KPROBE_BP,
-	}
-};
-
-static const union loongarch_instruction singlestep_insn = {
-	.reg0i15_format = {
-		.opcode = break_op,
-		.immediate = BRK_KPROBE_SSTEPBP,
-	}
-};
+#define KPROBE_BP_INSN		larch_insn_gen_break(BRK_KPROBE_BP)
+#define KPROBE_SSTEPBP_INSN	larch_insn_gen_break(BRK_KPROBE_SSTEPBP)
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe);
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -24,7 +13,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 static void arch_prepare_ss_slot(struct kprobe *p)
 {
 	p->ainsn.insn[0] = *p->addr;
-	p->ainsn.insn[1] = singlestep_insn;
+	p->ainsn.insn[1] = KPROBE_SSTEPBP_INSN;
 	p->ainsn.restore = (unsigned long)p->addr + LOONGARCH_INSN_SIZE;
 }
 NOKPROBE_SYMBOL(arch_prepare_ss_slot);
@@ -37,17 +26,20 @@ NOKPROBE_SYMBOL(arch_prepare_simulate);
 
 int arch_prepare_kprobe(struct kprobe *p)
 {
+	union loongarch_instruction insn;
+
 	if ((unsigned long)p->addr & 0x3)
 		return -EILSEQ;
 
 	/* copy instruction */
 	p->opcode = *p->addr;
+	insn.word = p->opcode;
 
 	/* decode instruction */
-	if (insns_not_supported(p->opcode))
+	if (insns_not_supported(insn))
 		return -EINVAL;
 
-	if (insns_need_simulation(p->opcode)) {
+	if (insns_need_simulation(insn)) {
 		p->ainsn.insn = NULL;
 	} else {
 		p->ainsn.insn = get_insn_slot();
@@ -68,7 +60,7 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe);
 /* Install breakpoint in text */
 void arch_arm_kprobe(struct kprobe *p)
 {
-	*p->addr = breakpoint_insn;
+	*p->addr = KPROBE_BP_INSN;
 	flush_insn_slot(p);
 }
 NOKPROBE_SYMBOL(arch_arm_kprobe);
@@ -163,6 +155,8 @@ NOKPROBE_SYMBOL(post_kprobe_handler);
 static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
 			     struct kprobe_ctlblk *kcb, int reenter)
 {
+	union loongarch_instruction insn;
+
 	if (reenter) {
 		save_previous_kprobe(kcb);
 		set_current_kprobe(p);
@@ -178,7 +172,8 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
 		regs->csr_era = (unsigned long)p->ainsn.insn;
 	} else {
 		/* simulate single steping */
-		arch_simulate_insn(p->opcode, regs);
+		insn.word = p->opcode;
+		arch_simulate_insn(insn, regs);
 		/* now go for post processing */
 		post_kprobe_handler(p, kcb, regs);
 	}
@@ -253,7 +248,7 @@ bool kprobe_breakpoint_handler(struct pt_regs *regs)
 		}
 	}
 
-	if (addr->word != breakpoint_insn.word) {
+	if (*addr != KPROBE_BP_INSN) {
 		/*
 		 * The breakpoint instruction was removed right
 		 * after we hit it.  Another cpu has removed
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 4/6] LoongArch: Add uprobes support
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
                   ` (2 preceding siblings ...)
  2023-04-19  9:56 ` [PATCH v3 3/6] LoongArch: Use larch_insn_gen_break() for kprobes Tiezhu Yang
@ 2023-04-19  9:56 ` Tiezhu Yang
  2023-04-23 13:12   ` Huacai Chen
  2023-04-19  9:57 ` [PATCH v3 5/6] LoongArch: Check atomic instructions in insns_not_supported() Tiezhu Yang
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:56 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

Uprobes is the user-space counterpart to kprobes, this commit
adds uprobes support for LoongArch.

Here is a simple example with CONFIG_UPROBE_EVENTS=y:

  # cat test.c
  #include <stdio.h>

  int add(int a, int b)
  {
  	  return a + b;
  }

  int main()
  {
	  return add(2, 7);
  }
  # gcc test.c -o /tmp/test
  # nm /tmp/test | grep add
  0000000120004194 T add
  # cd /sys/kernel/debug/tracing
  # echo > uprobe_events
  # echo "p:myuprobe /tmp/test:0x4194 %r4 %r5" > uprobe_events
  # echo "r:myuretprobe /tmp/test:0x4194 %r4" >> uprobe_events
  # echo 1 > events/uprobes/enable
  # echo 1 > tracing_on
  # /tmp/test
  # cat trace
  ...
  #           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
  #              | |         |   |||||     |         |
              test-1060    [001] DNZff  1015.770620: myuprobe: (0x120004194) arg1=0x2 arg2=0x7
              test-1060    [001] DNZff  1015.770930: myuretprobe: (0x1200041f0 <- 0x120004194) arg1=0x9

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/Kconfig               |   3 +
 arch/loongarch/include/asm/uprobes.h |  36 +++++++++
 arch/loongarch/kernel/Makefile       |   1 +
 arch/loongarch/kernel/traps.c        |   9 +--
 arch/loongarch/kernel/uprobes.c      | 142 +++++++++++++++++++++++++++++++++++
 5 files changed, 186 insertions(+), 5 deletions(-)
 create mode 100644 arch/loongarch/include/asm/uprobes.h
 create mode 100644 arch/loongarch/kernel/uprobes.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 7fd5125..ab66ad2 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -574,6 +574,9 @@ config ARCH_MMAP_RND_BITS_MIN
 config ARCH_MMAP_RND_BITS_MAX
 	default 18
 
+config ARCH_SUPPORTS_UPROBES
+	def_bool y
+
 menu "Power management options"
 
 config ARCH_SUSPEND_POSSIBLE
diff --git a/arch/loongarch/include/asm/uprobes.h b/arch/loongarch/include/asm/uprobes.h
new file mode 100644
index 0000000..59e2683
--- /dev/null
+++ b/arch/loongarch/include/asm/uprobes.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_LOONGARCH_UPROBES_H
+#define __ASM_LOONGARCH_UPROBES_H
+
+#include <asm/inst.h>
+
+typedef u32 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES		8
+#define UPROBE_XOL_SLOT_BYTES	MAX_UINSN_BYTES
+
+#define UPROBE_XOLBP_INSN	larch_insn_gen_break(BRK_UPROBE_XOLBP)
+#define UPROBE_SWBP_INSN	larch_insn_gen_break(BRK_UPROBE_BP)
+#define UPROBE_SWBP_INSN_SIZE	LOONGARCH_INSN_SIZE
+
+struct arch_uprobe {
+	union {
+		u32 insn[2];
+		u32 ixol[2];
+	};
+	bool simulate;
+};
+
+struct arch_uprobe_task {
+	unsigned long saved_trap_nr;
+};
+
+#ifdef CONFIG_UPROBES
+bool uprobe_breakpoint_handler(struct pt_regs *regs);
+bool uprobe_singlestep_handler(struct pt_regs *regs);
+#else /* !CONFIG_UPROBES */
+static inline bool uprobe_breakpoint_handler(struct pt_regs *regs) { return false; }
+static inline bool uprobe_singlestep_handler(struct pt_regs *regs) { return false; }
+#endif /* CONFIG_UPROBES */
+
+#endif /* __ASM_LOONGARCH_UPROBES_H */
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 78d4e33..67b9c26 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -53,5 +53,6 @@ obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_regs.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 
 obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes_trampoline.o
+obj-$(CONFIG_UPROBES)		+= uprobes.o
 
 CPPFLAGS_vmlinux.lds		:= $(KBUILD_CFLAGS)
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index de8ebe2..cfc2e0c 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -45,6 +45,7 @@
 #include <asm/tlb.h>
 #include <asm/types.h>
 #include <asm/unwind.h>
+#include <asm/uprobes.h>
 
 #include "access-helper.h"
 
@@ -440,7 +441,6 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
 	if (regs->csr_prmd & CSR_PRMD_PIE)
 		local_irq_enable();
 
-	current->thread.trap_nr = read_csr_excode();
 	if (__get_inst(&opcode, (u32 *)era, user))
 		goto out_sigsegv;
 
@@ -462,18 +462,17 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
 		else
 			break;
 	case BRK_UPROBE_BP:
-		if (notify_die(DIE_UPROBE, "Uprobe", regs, bcode,
-			       current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
+		if (uprobe_breakpoint_handler(regs))
 			goto out;
 		else
 			break;
 	case BRK_UPROBE_XOLBP:
-		if (notify_die(DIE_UPROBE_XOL, "Uprobe_XOL", regs, bcode,
-			       current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
+		if (uprobe_singlestep_handler(regs))
 			goto out;
 		else
 			break;
 	default:
+		current->thread.trap_nr = read_csr_excode();
 		if (notify_die(DIE_TRAP, "Break", regs, bcode,
 			       current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
 			goto out;
diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c
new file mode 100644
index 0000000..628c39d
--- /dev/null
+++ b/arch/loongarch/kernel/uprobes.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/highmem.h>
+#include <linux/ptrace.h>
+#include <linux/uprobes.h>
+#include <linux/sched.h>
+#include <asm/cacheflush.h>
+
+#define UPROBE_TRAP_NR	UINT_MAX
+
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
+			     struct mm_struct *mm, unsigned long addr)
+{
+	union loongarch_instruction insn;
+
+	if (addr & 0x3)
+		return -EILSEQ;
+
+	insn.word = auprobe->insn[0];
+
+	if (insns_not_supported(insn))
+		return -EINVAL;
+
+	if (insns_need_simulation(insn)) {
+		auprobe->ixol[0] = larch_insn_gen_nop();
+		auprobe->simulate = true;
+	} else {
+		auprobe->ixol[0] = auprobe->insn[0];
+		auprobe->simulate = false;
+	}
+
+	auprobe->ixol[1] = UPROBE_XOLBP_INSN;
+
+	return 0;
+}
+
+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct uprobe_task *utask = current->utask;
+
+	utask->autask.saved_trap_nr = current->thread.trap_nr;
+	current->thread.trap_nr = UPROBE_TRAP_NR;
+	instruction_pointer_set(regs, utask->xol_vaddr);
+
+	return 0;
+}
+
+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct uprobe_task *utask = current->utask;
+
+	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
+	current->thread.trap_nr = utask->autask.saved_trap_nr;
+	instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
+
+	return 0;
+}
+
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	struct uprobe_task *utask = current->utask;
+
+	current->thread.trap_nr = utask->autask.saved_trap_nr;
+	instruction_pointer_set(regs, utask->vaddr);
+}
+
+bool arch_uprobe_xol_was_trapped(struct task_struct *t)
+{
+	if (t->thread.trap_nr != UPROBE_TRAP_NR)
+		return true;
+
+	return false;
+}
+
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+	union loongarch_instruction insn;
+
+	if (!auprobe->simulate)
+		return false;
+
+	insn.word = auprobe->insn[0];
+	arch_simulate_insn(insn, regs);
+
+	return true;
+}
+
+unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
+						struct pt_regs *regs)
+{
+	unsigned long ra = regs->regs[1];
+
+	regs->regs[1] = trampoline_vaddr;
+
+	return ra;
+}
+
+bool arch_uretprobe_is_alive(struct return_instance *ret,
+			     enum rp_check ctx, struct pt_regs *regs)
+{
+	if (ctx == RP_CHECK_CHAIN_CALL)
+		return regs->regs[3] <= ret->stack;
+	else
+		return regs->regs[3] < ret->stack;
+}
+
+int arch_uprobe_exception_notify(struct notifier_block *self,
+				 unsigned long val, void *data)
+{
+	return NOTIFY_DONE;
+}
+
+bool uprobe_breakpoint_handler(struct pt_regs *regs)
+{
+	if (uprobe_pre_sstep_notifier(regs))
+		return true;
+
+	return false;
+}
+
+bool uprobe_singlestep_handler(struct pt_regs *regs)
+{
+	if (uprobe_post_sstep_notifier(regs))
+		return true;
+
+	return false;
+}
+
+unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+	return instruction_pointer(regs);
+}
+
+void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
+			   void *src, unsigned long len)
+{
+	void *kaddr = kmap_local_page(page);
+	void *dst = kaddr + (vaddr & ~PAGE_MASK);
+
+	memcpy(dst, src, len);
+	flush_icache_range((unsigned long)dst, (unsigned long)dst + len);
+	kunmap_local(kaddr);
+}
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 5/6] LoongArch: Check atomic instructions in insns_not_supported()
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
                   ` (3 preceding siblings ...)
  2023-04-19  9:56 ` [PATCH v3 4/6] LoongArch: Add uprobes support Tiezhu Yang
@ 2023-04-19  9:57 ` Tiezhu Yang
  2023-04-19  9:57 ` [PATCH v3 6/6] LoongArch: Remove five DIE_* definitions in kdebug.h Tiezhu Yang
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:57 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

Like llsc instructions, the atomic memory access instructions should
not be supported for probing, check them in insns_not_supported().

Here is a simple example with CONFIG_UPROBE_EVENTS=y:

  # cat pthread.c
  #include <stdio.h>
  #include <stdlib.h>
  #include <pthread.h>

  static pthread_spinlock_t lock;
  static pthread_t t1, t2;
  static int count = 0;

  void *t1_start(void *arg)
  {
  	  for (int i = 0; i < 10000; i++)
	  {
		  pthread_spin_lock(&lock);
		  count++;
		  pthread_spin_unlock(&lock);
	  }
  }

  void *t2_start(void *arg)
  {
	  for (int i = 0; i < 20000; i++)
	  {
		  pthread_spin_lock(&lock);
		  count++;
		  pthread_spin_unlock(&lock);
	  }
  }

  int main()
  {
	  int ret;

	  ret = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
	  if (ret)
		  return -1;

	  ret = pthread_create(&t1, NULL, t1_start, NULL);
	  if (ret)
		  exit(1);

	  ret = pthread_create(&t2, NULL, t2_start, NULL);
	  if (ret)
		  exit(1);

	  pthread_join(t1, NULL);
	  pthread_join(t2, NULL);
	  pthread_spin_destroy(&lock);

	  printf("%d\n", count);
	  return 0;
  }
  # gcc pthread.c -o /tmp/pthread
  # objdump -d /lib64/libc.so.6 | grep -w "pthread_spin_lock" -A 5 | head -5
  00000000000886a4 <pthread_spin_lock@@GLIBC_2.36>:
     886a4:	  0280040d 	  addi.w      	  $t1, $zero, 1(0x1)
     886a8:	  3869348c 	  amswap_db.w 	  $t0, $t1, $a0
     886ac:	  0040818c 	  slli.w      	  $t0, $t0, 0x0
     886b0:	  44003180 	  bnez        	  $t0, 48(0x30)	  # 886e0 <pthread_spin_lock@@GLIBC_2.36+0x3c>
  # cd /sys/kernel/debug/tracing
  # echo > uprobe_events
  # echo "p:myuprobe /lib64/libc.so.6:0x886a4" > uprobe_events

Without this patch:

  # echo 1 > events/uprobes/enable
  # echo 1 > tracing_on
  # /tmp/pthread
  Trace/breakpoint trap (core dumped)

With this patch:

  # echo 1 > events/uprobes/enable
  bash: echo: write error: Invalid argument

Reported-by: Hengqi Chen <hengqi.chen@gmail.com>
Link: https://lore.kernel.org/all/SY4P282MB351877A70A0333C790FE85A5C09C9@SY4P282MB3518.AUSP282.PROD.OUTLOOK.COM/
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/include/asm/inst.h | 26 ++++++++++++++++++++++++++
 arch/loongarch/kernel/inst.c      |  6 ++++++
 arch/loongarch/kernel/uprobes.c   |  9 +++++----
 3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 061c0ea..09d5656 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -176,6 +176,32 @@ enum reg3_op {
 	amord_op	= 0x70c7,
 	amxorw_op	= 0x70c8,
 	amxord_op	= 0x70c9,
+	ammaxw_op	= 0x70ca,
+	ammaxd_op	= 0x70cb,
+	amminw_op	= 0x70cc,
+	ammind_op	= 0x70cd,
+	ammaxwu_op	= 0x70ce,
+	ammaxdu_op	= 0x70cf,
+	amminwu_op	= 0x70d0,
+	ammindu_op	= 0x70d1,
+	amswapdbw_op	= 0x70d2,
+	amswapdbd_op	= 0x70d3,
+	amadddbw_op	= 0x70d4,
+	amadddbd_op	= 0x70d5,
+	amanddbw_op	= 0x70d6,
+	amanddbd_op	= 0x70d7,
+	amordbw_op	= 0x70d8,
+	amordbd_op	= 0x70d9,
+	amxordbw_op	= 0x70da,
+	amxordbd_op	= 0x70db,
+	ammaxdbw_op	= 0x70dc,
+	ammaxdbd_op	= 0x70dd,
+	ammindbw_op	= 0x70de,
+	ammindbd_op	= 0x70df,
+	ammaxdbwu_op	= 0x70e0,
+	ammaxdbdu_op	= 0x70e1,
+	ammindbwu_op	= 0x70e2,
+	ammindbdu_op	= 0x70e3,
 };
 
 enum reg3sa2_op {
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index 1d7d579..ce25a63 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -135,6 +135,12 @@ void simu_branch(struct pt_regs *regs, union loongarch_instruction insn)
 
 bool insns_not_supported(union loongarch_instruction insn)
 {
+	switch (insn.reg3_format.opcode) {
+	case amswapw_op ... ammindbdu_op:
+		pr_notice("atomic memory access instructions are not supported\n");
+		return true;
+	}
+
 	switch (insn.reg2i14_format.opcode) {
 	case llw_op:
 	case lld_op:
diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c
index 628c39d..bc6ec74 100644
--- a/arch/loongarch/kernel/uprobes.c
+++ b/arch/loongarch/kernel/uprobes.c
@@ -15,10 +15,11 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
 	if (addr & 0x3)
 		return -EILSEQ;
 
-	insn.word = auprobe->insn[0];
-
-	if (insns_not_supported(insn))
-		return -EINVAL;
+	for (int idx = ARRAY_SIZE(auprobe->insn) - 1; idx >= 0; idx--) {
+		insn.word = auprobe->insn[idx];
+		if (insns_not_supported(insn))
+			return -EINVAL;
+	}
 
 	if (insns_need_simulation(insn)) {
 		auprobe->ixol[0] = larch_insn_gen_nop();
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 6/6] LoongArch: Remove five DIE_* definitions in kdebug.h
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
                   ` (4 preceding siblings ...)
  2023-04-19  9:57 ` [PATCH v3 5/6] LoongArch: Check atomic instructions in insns_not_supported() Tiezhu Yang
@ 2023-04-19  9:57 ` Tiezhu Yang
  2023-04-28 11:05 ` [PATCH v3 0/6] Add uprobes support for LoongArch Jeff Xie
  2023-05-04  2:03 ` Hengqi Chen
  7 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-19  9:57 UTC (permalink / raw)
  To: Huacai Chen, WANG Xuerui; +Cc: loongarch, linux-kernel, loongson-kernel

For now, DIE_PAGE_FAULT, DIE_BREAK, DIE_SSTEPBP, DIE_UPROBE
and DIE_UPROBE_XOL are not used by any code, remove them.

Suggested-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 arch/loongarch/include/asm/kdebug.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/loongarch/include/asm/kdebug.h b/arch/loongarch/include/asm/kdebug.h
index d721b4b..c00ed87 100644
--- a/arch/loongarch/include/asm/kdebug.h
+++ b/arch/loongarch/include/asm/kdebug.h
@@ -13,11 +13,6 @@ enum die_val {
 	DIE_FP,
 	DIE_SIMD,
 	DIE_TRAP,
-	DIE_PAGE_FAULT,
-	DIE_BREAK,
-	DIE_SSTEPBP,
-	DIE_UPROBE,
-	DIE_UPROBE_XOL,
 };
 
 #endif /* _ASM_LOONGARCH_KDEBUG_H */
-- 
2.1.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 4/6] LoongArch: Add uprobes support
  2023-04-19  9:56 ` [PATCH v3 4/6] LoongArch: Add uprobes support Tiezhu Yang
@ 2023-04-23 13:12   ` Huacai Chen
  2023-04-24  1:19     ` Tiezhu Yang
  0 siblings, 1 reply; 11+ messages in thread
From: Huacai Chen @ 2023-04-23 13:12 UTC (permalink / raw)
  To: Tiezhu Yang; +Cc: WANG Xuerui, loongarch, linux-kernel, loongson-kernel

Hi, Tiezhu,

On Wed, Apr 19, 2023 at 5:57 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> Uprobes is the user-space counterpart to kprobes, this commit
> adds uprobes support for LoongArch.
>
> Here is a simple example with CONFIG_UPROBE_EVENTS=y:
>
>   # cat test.c
>   #include <stdio.h>
>
>   int add(int a, int b)
>   {
>           return a + b;
>   }
>
>   int main()
>   {
>           return add(2, 7);
>   }
>   # gcc test.c -o /tmp/test
>   # nm /tmp/test | grep add
>   0000000120004194 T add
>   # cd /sys/kernel/debug/tracing
>   # echo > uprobe_events
>   # echo "p:myuprobe /tmp/test:0x4194 %r4 %r5" > uprobe_events
>   # echo "r:myuretprobe /tmp/test:0x4194 %r4" >> uprobe_events
>   # echo 1 > events/uprobes/enable
>   # echo 1 > tracing_on
>   # /tmp/test
>   # cat trace
>   ...
>   #           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
>   #              | |         |   |||||     |         |
>               test-1060    [001] DNZff  1015.770620: myuprobe: (0x120004194) arg1=0x2 arg2=0x7
>               test-1060    [001] DNZff  1015.770930: myuretprobe: (0x1200041f0 <- 0x120004194) arg1=0x9
>
> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
> ---
>  arch/loongarch/Kconfig               |   3 +
>  arch/loongarch/include/asm/uprobes.h |  36 +++++++++
>  arch/loongarch/kernel/Makefile       |   1 +
>  arch/loongarch/kernel/traps.c        |   9 +--
>  arch/loongarch/kernel/uprobes.c      | 142 +++++++++++++++++++++++++++++++++++
>  5 files changed, 186 insertions(+), 5 deletions(-)
>  create mode 100644 arch/loongarch/include/asm/uprobes.h
>  create mode 100644 arch/loongarch/kernel/uprobes.c
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 7fd5125..ab66ad2 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -574,6 +574,9 @@ config ARCH_MMAP_RND_BITS_MIN
>  config ARCH_MMAP_RND_BITS_MAX
>         default 18
>
> +config ARCH_SUPPORTS_UPROBES
> +       def_bool y
> +
>  menu "Power management options"
>
>  config ARCH_SUSPEND_POSSIBLE
> diff --git a/arch/loongarch/include/asm/uprobes.h b/arch/loongarch/include/asm/uprobes.h
> new file mode 100644
> index 0000000..59e2683
> --- /dev/null
> +++ b/arch/loongarch/include/asm/uprobes.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_LOONGARCH_UPROBES_H
> +#define __ASM_LOONGARCH_UPROBES_H
> +
> +#include <asm/inst.h>
> +
> +typedef u32 uprobe_opcode_t;
> +
> +#define MAX_UINSN_BYTES                8
> +#define UPROBE_XOL_SLOT_BYTES  MAX_UINSN_BYTES
In old versions we define UPROBE_XOL_SLOT_BYTES to 128, why we use 8 now?

> +
> +#define UPROBE_XOLBP_INSN      larch_insn_gen_break(BRK_UPROBE_XOLBP)
> +#define UPROBE_SWBP_INSN       larch_insn_gen_break(BRK_UPROBE_BP)
> +#define UPROBE_SWBP_INSN_SIZE  LOONGARCH_INSN_SIZE
> +
> +struct arch_uprobe {
> +       union {
> +               u32 insn[2];
> +               u32 ixol[2];
> +       };
> +       bool simulate;
> +};
> +
> +struct arch_uprobe_task {
> +       unsigned long saved_trap_nr;
> +};
> +
> +#ifdef CONFIG_UPROBES
> +bool uprobe_breakpoint_handler(struct pt_regs *regs);
> +bool uprobe_singlestep_handler(struct pt_regs *regs);
> +#else /* !CONFIG_UPROBES */
> +static inline bool uprobe_breakpoint_handler(struct pt_regs *regs) { return false; }
> +static inline bool uprobe_singlestep_handler(struct pt_regs *regs) { return false; }
> +#endif /* CONFIG_UPROBES */
> +
> +#endif /* __ASM_LOONGARCH_UPROBES_H */
> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> index 78d4e33..67b9c26 100644
> --- a/arch/loongarch/kernel/Makefile
> +++ b/arch/loongarch/kernel/Makefile
> @@ -53,5 +53,6 @@ obj-$(CONFIG_PERF_EVENTS)     += perf_event.o perf_regs.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
>
>  obj-$(CONFIG_KPROBES)          += kprobes.o kprobes_trampoline.o
> +obj-$(CONFIG_UPROBES)          += uprobes.o
>
>  CPPFLAGS_vmlinux.lds           := $(KBUILD_CFLAGS)
> diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
> index de8ebe2..cfc2e0c 100644
> --- a/arch/loongarch/kernel/traps.c
> +++ b/arch/loongarch/kernel/traps.c
> @@ -45,6 +45,7 @@
>  #include <asm/tlb.h>
>  #include <asm/types.h>
>  #include <asm/unwind.h>
> +#include <asm/uprobes.h>
>
>  #include "access-helper.h"
>
> @@ -440,7 +441,6 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
>         if (regs->csr_prmd & CSR_PRMD_PIE)
>                 local_irq_enable();
>
> -       current->thread.trap_nr = read_csr_excode();
>         if (__get_inst(&opcode, (u32 *)era, user))
>                 goto out_sigsegv;
>
> @@ -462,18 +462,17 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
>                 else
>                         break;
>         case BRK_UPROBE_BP:
> -               if (notify_die(DIE_UPROBE, "Uprobe", regs, bcode,
> -                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
> +               if (uprobe_breakpoint_handler(regs))
>                         goto out;
>                 else
>                         break;
>         case BRK_UPROBE_XOLBP:
> -               if (notify_die(DIE_UPROBE_XOL, "Uprobe_XOL", regs, bcode,
> -                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
> +               if (uprobe_singlestep_handler(regs))
As I know, XOL means "execute out of line", is it an alias of "single step"?

Huacai
>                         goto out;
>                 else
>                         break;
>         default:
> +               current->thread.trap_nr = read_csr_excode();
>                 if (notify_die(DIE_TRAP, "Break", regs, bcode,
>                                current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
>                         goto out;
> diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c
> new file mode 100644
> index 0000000..628c39d
> --- /dev/null
> +++ b/arch/loongarch/kernel/uprobes.c
> @@ -0,0 +1,142 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +#include <linux/highmem.h>
> +#include <linux/ptrace.h>
> +#include <linux/uprobes.h>
> +#include <linux/sched.h>
> +#include <asm/cacheflush.h>
> +
> +#define UPROBE_TRAP_NR UINT_MAX
> +
> +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
> +                            struct mm_struct *mm, unsigned long addr)
> +{
> +       union loongarch_instruction insn;
> +
> +       if (addr & 0x3)
> +               return -EILSEQ;
> +
> +       insn.word = auprobe->insn[0];
> +
> +       if (insns_not_supported(insn))
> +               return -EINVAL;
> +
> +       if (insns_need_simulation(insn)) {
> +               auprobe->ixol[0] = larch_insn_gen_nop();
> +               auprobe->simulate = true;
> +       } else {
> +               auprobe->ixol[0] = auprobe->insn[0];
> +               auprobe->simulate = false;
> +       }
> +
> +       auprobe->ixol[1] = UPROBE_XOLBP_INSN;
> +
> +       return 0;
> +}
> +
> +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> +       struct uprobe_task *utask = current->utask;
> +
> +       utask->autask.saved_trap_nr = current->thread.trap_nr;
> +       current->thread.trap_nr = UPROBE_TRAP_NR;
> +       instruction_pointer_set(regs, utask->xol_vaddr);
> +
> +       return 0;
> +}
> +
> +int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> +       struct uprobe_task *utask = current->utask;
> +
> +       WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
> +       current->thread.trap_nr = utask->autask.saved_trap_nr;
> +       instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
> +
> +       return 0;
> +}
> +
> +void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> +       struct uprobe_task *utask = current->utask;
> +
> +       current->thread.trap_nr = utask->autask.saved_trap_nr;
> +       instruction_pointer_set(regs, utask->vaddr);
> +}
> +
> +bool arch_uprobe_xol_was_trapped(struct task_struct *t)
> +{
> +       if (t->thread.trap_nr != UPROBE_TRAP_NR)
> +               return true;
> +
> +       return false;
> +}
> +
> +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> +       union loongarch_instruction insn;
> +
> +       if (!auprobe->simulate)
> +               return false;
> +
> +       insn.word = auprobe->insn[0];
> +       arch_simulate_insn(insn, regs);
> +
> +       return true;
> +}
> +
> +unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
> +                                               struct pt_regs *regs)
> +{
> +       unsigned long ra = regs->regs[1];
> +
> +       regs->regs[1] = trampoline_vaddr;
> +
> +       return ra;
> +}
> +
> +bool arch_uretprobe_is_alive(struct return_instance *ret,
> +                            enum rp_check ctx, struct pt_regs *regs)
> +{
> +       if (ctx == RP_CHECK_CHAIN_CALL)
> +               return regs->regs[3] <= ret->stack;
> +       else
> +               return regs->regs[3] < ret->stack;
> +}
> +
> +int arch_uprobe_exception_notify(struct notifier_block *self,
> +                                unsigned long val, void *data)
> +{
> +       return NOTIFY_DONE;
> +}
> +
> +bool uprobe_breakpoint_handler(struct pt_regs *regs)
> +{
> +       if (uprobe_pre_sstep_notifier(regs))
> +               return true;
> +
> +       return false;
> +}
> +
> +bool uprobe_singlestep_handler(struct pt_regs *regs)
> +{
> +       if (uprobe_post_sstep_notifier(regs))
> +               return true;
> +
> +       return false;
> +}
> +
> +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
> +{
> +       return instruction_pointer(regs);
> +}
> +
> +void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
> +                          void *src, unsigned long len)
> +{
> +       void *kaddr = kmap_local_page(page);
> +       void *dst = kaddr + (vaddr & ~PAGE_MASK);
> +
> +       memcpy(dst, src, len);
> +       flush_icache_range((unsigned long)dst, (unsigned long)dst + len);
> +       kunmap_local(kaddr);
> +}
> --
> 2.1.0
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 4/6] LoongArch: Add uprobes support
  2023-04-23 13:12   ` Huacai Chen
@ 2023-04-24  1:19     ` Tiezhu Yang
  0 siblings, 0 replies; 11+ messages in thread
From: Tiezhu Yang @ 2023-04-24  1:19 UTC (permalink / raw)
  To: Huacai Chen; +Cc: WANG Xuerui, loongarch, linux-kernel, loongson-kernel



On 04/23/2023 09:12 PM, Huacai Chen wrote:
> Hi, Tiezhu,
>
> On Wed, Apr 19, 2023 at 5:57 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>>
>> Uprobes is the user-space counterpart to kprobes, this commit
>> adds uprobes support for LoongArch.

...

>> +#define MAX_UINSN_BYTES                8
>> +#define UPROBE_XOL_SLOT_BYTES  MAX_UINSN_BYTES
> In old versions we define UPROBE_XOL_SLOT_BYTES to 128, why we use 8 now?

I assume "the old version" maybe comes from mips, I am not quite sure 
the backgrounds. For LoongArch, there are 2 xol slots to save 2 
instructions, each of them is 32 bit, 2*32bit=8bytes, so 
UPROBE_XOL_SLOT_BYTES can be 8.

>> +
>> +#define UPROBE_XOLBP_INSN      larch_insn_gen_break(BRK_UPROBE_XOLBP)
>> +#define UPROBE_SWBP_INSN       larch_insn_gen_break(BRK_UPROBE_BP)
>> +#define UPROBE_SWBP_INSN_SIZE  LOONGARCH_INSN_SIZE

...

>>         case BRK_UPROBE_XOLBP:
>> -               if (notify_die(DIE_UPROBE_XOL, "Uprobe_XOL", regs, bcode,
>> -                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
>> +               if (uprobe_singlestep_handler(regs))
> As I know, XOL means "execute out of line", is it an alias of "single step"?

I think so, the instruction filled in xol slots is to single step, 
arm64, riscv, csky also uses "single step" for the related code, 
powerpc, s390 uses "DIE_SSTEP".

Thanks,
Tiezhu


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 0/6] Add uprobes support for LoongArch
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
                   ` (5 preceding siblings ...)
  2023-04-19  9:57 ` [PATCH v3 6/6] LoongArch: Remove five DIE_* definitions in kdebug.h Tiezhu Yang
@ 2023-04-28 11:05 ` Jeff Xie
  2023-05-04  2:03 ` Hengqi Chen
  7 siblings, 0 replies; 11+ messages in thread
From: Jeff Xie @ 2023-04-28 11:05 UTC (permalink / raw)
  To: Tiezhu Yang
  Cc: Huacai Chen, WANG Xuerui, loongarch, linux-kernel, loongson-kernel

Hi Tiezhu,

I have tested the uprobe patchset and found that:

# perf probe -x /lib/libc.so.6 malloc
# perf record -e probe_libc:malloc -aR sleep 30

Then the OS will hang forever and the problem can always be reproduced.

On Wed, Apr 19, 2023 at 6:10 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> v3:
>   -- Check atomic instructions in insns_not_supported()
>   -- Remove five DIE_* definitions in kdebug.h
>
> v2:
>   -- Move the functions to inst.c in patch #1
>   -- Pass around union for insns_not_supported(),
>      insns_need_simulation() and arch_simulate_insn()
>
> v1:
>   -- Split the RFC patch #2 into two patches
>   -- Use larch_insn_gen_break() to generate break insns
>      for kprobes and uprobes
>   -- Pass around instruction word instead of union for
>      insns_not_supported(), insns_need_simulation() and
>      arch_simulate_insn() to avoid type conversion for callers
>   -- Add a simple test case for uprobes in the commit message
>
> Tiezhu Yang (6):
>   LoongArch: Move three functions from kprobes.c to inst.c
>   LoongArch: Add larch_insn_gen_break() to generate break insns
>   LoongArch: Use larch_insn_gen_break() for kprobes
>   LoongArch: Add uprobes support
>   LoongArch: Check atomic instructions in insns_not_supported()
>   LoongArch: Remove five DIE_* definitions in kdebug.h
>
>  arch/loongarch/Kconfig               |   3 +
>  arch/loongarch/include/asm/inst.h    |  42 ++++++++++
>  arch/loongarch/include/asm/kdebug.h  |   5 --
>  arch/loongarch/include/asm/kprobes.h |   2 +-
>  arch/loongarch/include/asm/uprobes.h |  36 +++++++++
>  arch/loongarch/kernel/Makefile       |   1 +
>  arch/loongarch/kernel/inst.c         |  54 +++++++++++++
>  arch/loongarch/kernel/kprobes.c      |  75 ++++--------------
>  arch/loongarch/kernel/traps.c        |   9 +--
>  arch/loongarch/kernel/uprobes.c      | 143 +++++++++++++++++++++++++++++++++++
>  10 files changed, 298 insertions(+), 72 deletions(-)
>  create mode 100644 arch/loongarch/include/asm/uprobes.h
>  create mode 100644 arch/loongarch/kernel/uprobes.c
>
> --
> 2.1.0
>


-- 
Thanks,
JeffXie

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 0/6] Add uprobes support for LoongArch
  2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
                   ` (6 preceding siblings ...)
  2023-04-28 11:05 ` [PATCH v3 0/6] Add uprobes support for LoongArch Jeff Xie
@ 2023-05-04  2:03 ` Hengqi Chen
  7 siblings, 0 replies; 11+ messages in thread
From: Hengqi Chen @ 2023-05-04  2:03 UTC (permalink / raw)
  To: Tiezhu Yang, Huacai Chen, WANG Xuerui
  Cc: loongarch, linux-kernel, loongson-kernel



On 2023/4/19 17:56, Tiezhu Yang wrote:
> v3:
>   -- Check atomic instructions in insns_not_supported()
>   -- Remove five DIE_* definitions in kdebug.h
> 
> v2:
>   -- Move the functions to inst.c in patch #1
>   -- Pass around union for insns_not_supported(),
>      insns_need_simulation() and arch_simulate_insn()
> 
> v1:
>   -- Split the RFC patch #2 into two patches
>   -- Use larch_insn_gen_break() to generate break insns
>      for kprobes and uprobes
>   -- Pass around instruction word instead of union for
>      insns_not_supported(), insns_need_simulation() and
>      arch_simulate_insn() to avoid type conversion for callers
>   -- Add a simple test case for uprobes in the commit message
> 
> Tiezhu Yang (6):
>   LoongArch: Move three functions from kprobes.c to inst.c
>   LoongArch: Add larch_insn_gen_break() to generate break insns
>   LoongArch: Use larch_insn_gen_break() for kprobes
>   LoongArch: Add uprobes support
>   LoongArch: Check atomic instructions in insns_not_supported()
>   LoongArch: Remove five DIE_* definitions in kdebug.h
> 
>  arch/loongarch/Kconfig               |   3 +
>  arch/loongarch/include/asm/inst.h    |  42 ++++++++++
>  arch/loongarch/include/asm/kdebug.h  |   5 --
>  arch/loongarch/include/asm/kprobes.h |   2 +-
>  arch/loongarch/include/asm/uprobes.h |  36 +++++++++
>  arch/loongarch/kernel/Makefile       |   1 +
>  arch/loongarch/kernel/inst.c         |  54 +++++++++++++
>  arch/loongarch/kernel/kprobes.c      |  75 ++++--------------
>  arch/loongarch/kernel/traps.c        |   9 +--
>  arch/loongarch/kernel/uprobes.c      | 143 +++++++++++++++++++++++++++++++++++
>  10 files changed, 298 insertions(+), 72 deletions(-)
>  create mode 100644 arch/loongarch/include/asm/uprobes.h
>  create mode 100644 arch/loongarch/kernel/uprobes.c
> 

For the series,

Tested-by: Hengqi Chen <hengqi.chen@gmail.com>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2023-05-04  2:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-19  9:56 [PATCH v3 0/6] Add uprobes support for LoongArch Tiezhu Yang
2023-04-19  9:56 ` [PATCH v3 1/6] LoongArch: Move three functions from kprobes.c to inst.c Tiezhu Yang
2023-04-19  9:56 ` [PATCH v3 2/6] LoongArch: Add larch_insn_gen_break() to generate break insns Tiezhu Yang
2023-04-19  9:56 ` [PATCH v3 3/6] LoongArch: Use larch_insn_gen_break() for kprobes Tiezhu Yang
2023-04-19  9:56 ` [PATCH v3 4/6] LoongArch: Add uprobes support Tiezhu Yang
2023-04-23 13:12   ` Huacai Chen
2023-04-24  1:19     ` Tiezhu Yang
2023-04-19  9:57 ` [PATCH v3 5/6] LoongArch: Check atomic instructions in insns_not_supported() Tiezhu Yang
2023-04-19  9:57 ` [PATCH v3 6/6] LoongArch: Remove five DIE_* definitions in kdebug.h Tiezhu Yang
2023-04-28 11:05 ` [PATCH v3 0/6] Add uprobes support for LoongArch Jeff Xie
2023-05-04  2:03 ` Hengqi Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®