All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] LoongArch: Add ftrace support
@ 2022-08-19  8:13 Qing Zhang
  2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

This patch series to support basic and dynamic ftrace.

1) -pg
Use `-pg` makes stub like a child function `void _mcount(void *ra)`.
Thus, it can be seen store RA and open stack before `call _mcount`.
Find `open stack` at first, and then find `store RA`.

2) -fpatchable-function-entry=2
The compiler has inserted 2 NOPs before the regular function prologue.
T series registers are available and safe because of LoongArch psABI.

At runtime, replace nop with bl to enable ftrace call and replace bl with
nop to disable ftrace call. The bl requires us to save the original RA value,
so here it saves RA at t0.
details are:

| Compiled   |       Disabled         |        Enabled         |
+------------+------------------------+------------------------+
| nop        | move     t0, ra        | move     t0, ra        |
| nop        | nop                    | bl      ftrace_caller  |
| func_body  | func_body              | func_body              |

The RA value will be recovered by ftrace_regs_entry, and restored into RA
before returning to the regular function prologue. When a function is not
being traced, the move t0, ra is not harmful.

performs a series of startup tests on ftrace and The test cases in selftests
has passed on LoongArch.

Qing Zhang (9):
  LoongArch/ftrace: Add basic support
  LoongArch/ftrace: Add recordmcount support
  LoongArch/ftrace: Add dynamic function tracer support
  Loongarch/ftrace: Add dynamic function graph tracer support
  Loongarch/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support
  LoongArch: modules/ftrace: Initialize PLT at load time
  Loongarch/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
  LoongArch: ftrace: Add CALLER_ADDRx macros
  LoongArch: Enable CONFIG_KALLSYMS_ALL and CONFIG_DEBUG_FS

 arch/loongarch/Kconfig                     |   6 +
 arch/loongarch/Makefile                    |   5 +
 arch/loongarch/configs/loongson3_defconfig |  60 ++---
 arch/loongarch/include/asm/ftrace.h        |  46 ++++
 arch/loongarch/include/asm/inst.h          |  35 +++
 arch/loongarch/include/asm/module.h        |  14 +-
 arch/loongarch/include/asm/module.lds.h    |   1 +
 arch/loongarch/include/asm/processor.h     |   2 -
 arch/loongarch/include/asm/unwind.h        |   1 +
 arch/loongarch/kernel/Makefile             |  17 +-
 arch/loongarch/kernel/entry_dyn.S          | 154 +++++++++++++
 arch/loongarch/kernel/ftrace.c             |  74 ++++++
 arch/loongarch/kernel/ftrace_dyn.c         | 252 +++++++++++++++++++++
 arch/loongarch/kernel/inst.c               | 129 +++++++++++
 arch/loongarch/kernel/mcount.S             |  94 ++++++++
 arch/loongarch/kernel/module-sections.c    |  11 +
 arch/loongarch/kernel/module.c             |  48 ++++
 arch/loongarch/kernel/return_address.c     |  45 ++++
 arch/loongarch/kernel/unwind_guess.c       |   4 +-
 arch/loongarch/kernel/unwind_prologue.c    |  10 +-
 scripts/recordmcount.c                     |  23 ++
 21 files changed, 973 insertions(+), 58 deletions(-)
 create mode 100644 arch/loongarch/include/asm/ftrace.h
 create mode 100644 arch/loongarch/kernel/entry_dyn.S
 create mode 100644 arch/loongarch/kernel/ftrace.c
 create mode 100644 arch/loongarch/kernel/ftrace_dyn.c
 create mode 100644 arch/loongarch/kernel/mcount.S
 create mode 100644 arch/loongarch/kernel/return_address.c

-- 
2.36.1


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

* [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
@ 2022-08-19  8:13 ` Qing Zhang
  2022-08-19  9:29   ` Jinyang He
  2022-08-19 17:25   ` Steven Rostedt
  2022-08-19  8:13 ` [PATCH 2/9] LoongArch/ftrace: Add recordmcount support Qing Zhang
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

This patch contains basic ftrace support for LoongArch.
Specifically, function tracer (HAVE_FUNCTION_TRACER), function graph
tracer (HAVE_FUNCTION_GRAPH_TRACER) are implemented following the
instructions in Documentation/trace/ftrace-design.txt.

Use `-pg` makes stub like a child function `void _mcount(void *ra)`.
Thus, it can be seen store RA and open stack before `call _mcount`.
Find `open stack` at first, and then find `store RA`

Note that the functions in both inst.c and time.c should not be
hooked with the compiler's -pg option: to prevent infinite self-
referencing for the former, and to ignore early setup stuff for the
latter.

Co-developed-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
---
 arch/loongarch/Kconfig              |  2 +
 arch/loongarch/Makefile             |  5 ++
 arch/loongarch/include/asm/ftrace.h | 18 ++++++
 arch/loongarch/kernel/Makefile      |  8 +++
 arch/loongarch/kernel/ftrace.c      | 74 +++++++++++++++++++++++
 arch/loongarch/kernel/mcount.S      | 94 +++++++++++++++++++++++++++++
 6 files changed, 201 insertions(+)
 create mode 100644 arch/loongarch/include/asm/ftrace.h
 create mode 100644 arch/loongarch/kernel/ftrace.c
 create mode 100644 arch/loongarch/kernel/mcount.S

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 4abc9a28aba4..703a2c3a8e0d 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -84,6 +84,8 @@ config LOONGARCH
 	select HAVE_DMA_CONTIGUOUS
 	select HAVE_EXIT_THREAD
 	select HAVE_FAST_GUP
+        select HAVE_FUNCTION_GRAPH_TRACER
+        select HAVE_FUNCTION_TRACER
 	select HAVE_GENERIC_VDSO
 	select HAVE_IOREMAP_PROT
 	select HAVE_IRQ_EXIT_ON_IRQ_STACK
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index ec3de6191276..44f11a2937e9 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -29,6 +29,11 @@ ifneq ($(SUBARCH),$(ARCH))
   endif
 endif
 
+ifdef CONFIG_DYNAMIC_FTRACE
+  KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
+  CC_FLAGS_FTRACE := -fpatchable-function-entry=2
+endif
+
 ifdef CONFIG_64BIT
 ld-emul			= $(64bit-emul)
 cflags-y		+= -mabi=lp64s
diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
new file mode 100644
index 000000000000..6a3e76234618
--- /dev/null
+++ b/arch/loongarch/include/asm/ftrace.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_LOONGARCH_FTRACE_H
+#define _ASM_LOONGARCH_FTRACE_H
+
+#ifdef CONFIG_FUNCTION_TRACER
+#define MCOUNT_INSN_SIZE 4		/* sizeof mcount call */
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+#define mcount _mcount
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_TRACER */
+#endif /* _ASM_LOONGARCH_FTRACE_H */
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index e5be17009fe8..0a745d24d3e5 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -14,6 +14,14 @@ obj-$(CONFIG_EFI) 		+= efi.o
 
 obj-$(CONFIG_CPU_HAS_FPU)	+= fpu.o
 
+ifdef CONFIG_FUNCTION_TRACER
+    obj-y += mcount.o ftrace.o
+    CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+  CFLAGS_REMOVE_inst.o = $(CC_FLAGS_FTRACE)
+  CFLAGS_REMOVE_time.o = $(CC_FLAGS_FTRACE)
+  CFLAGS_REMOVE_perf_event.o = $(CC_FLAGS_FTRACE)
+endif
+
 obj-$(CONFIG_MODULES)		+= module.o module-sections.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 
diff --git a/arch/loongarch/kernel/ftrace.c b/arch/loongarch/kernel/ftrace.c
new file mode 100644
index 000000000000..c8ddc5f11f32
--- /dev/null
+++ b/arch/loongarch/kernel/ftrace.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/ftrace.h>
+#include <linux/syscalls.h>
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cacheflush.h>
+#include <asm/inst.h>
+#include <asm/loongarch.h>
+#include <asm/syscall.h>
+#include <asm/unistd.h>
+
+#include <asm-generic/sections.h>
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/*
+ * As `call _mcount` follows LoongArch psABI, ra-saved operation and
+ * stack operation can be found before this insn.
+ */
+
+static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off)
+{
+	union loongarch_instruction *insn;
+	int limit = 32;
+
+	insn = (union loongarch_instruction *)insn_addr;
+
+	do {
+		insn--;
+		limit--;
+
+		if (is_ra_save_ins(insn))
+			*ra_off = -((1 << 12) - insn->reg2i12_format.immediate);
+
+	} while (!is_stack_alloc_ins(insn) && limit);
+
+	if (!limit)
+		return -EINVAL;
+
+	return 0;
+}
+
+void prepare_ftrace_return(unsigned long self_addr,
+		unsigned long callsite_sp, unsigned long old)
+{
+	int ra_off;
+	unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+	if (unlikely(ftrace_graph_is_dead()))
+		return;
+
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		return;
+
+	if (ftrace_get_parent_ra_addr(self_addr, &ra_off))
+		goto out;
+
+	if (!function_graph_enter(old, self_addr, 0, NULL))
+		*(unsigned long *)(callsite_sp + ra_off) = return_hooker;
+
+	return;
+
+out:
+	ftrace_graph_stop();
+	WARN_ON(1);
+}
+#endif	/* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/loongarch/kernel/mcount.S b/arch/loongarch/kernel/mcount.S
new file mode 100644
index 000000000000..f1c1cc1a629e
--- /dev/null
+++ b/arch/loongarch/kernel/mcount.S
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * LoongArch specific _mcount support
+ *
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#include <asm/export.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/ftrace.h>
+
+	.text
+
+#define MCOUNT_STACK_SIZE	(2 * SZREG)
+#define MCOUNT_S0_OFFSET	(0)
+#define MCOUNT_RA_OFFSET	(SZREG)
+
+	.macro MCOUNT_SAVE_REGS
+	PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
+	PTR_S	s0, sp, MCOUNT_S0_OFFSET
+	PTR_S	ra, sp, MCOUNT_RA_OFFSET
+	move	s0, a0
+	.endm
+
+	.macro MCOUNT_RESTORE_REGS
+	move	a0, s0
+	PTR_L	ra, sp, MCOUNT_RA_OFFSET
+	PTR_L	s0, sp, MCOUNT_S0_OFFSET
+	PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
+	.endm
+
+
+SYM_FUNC_START(_mcount)
+	la	t1, ftrace_stub
+	la	t2, ftrace_trace_function	/* Prepare t2 for (1) */
+	PTR_L	t2, t2, 0
+	beq	t1, t2, fgraph_trace
+
+	MCOUNT_SAVE_REGS
+
+	move	a0, ra				/* arg0: self return address */
+	move	a1, s0				/* arg1: parent's return address */
+	jirl	ra, t2, 0			/* (1) call *ftrace_trace_function */
+
+	MCOUNT_RESTORE_REGS
+
+fgraph_trace:
+#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
+	la	t1, ftrace_stub
+	la	t3, ftrace_graph_return
+	PTR_L	t3, t3, 0
+	bne	t1, t3, ftrace_graph_caller
+	la	t1, ftrace_graph_entry_stub
+	la	t3, ftrace_graph_entry
+	PTR_L	t3, t3, 0
+	bne	t1, t3, ftrace_graph_caller
+#endif
+
+	.globl ftrace_stub
+ftrace_stub:
+	jirl	zero, ra, 0
+SYM_FUNC_END(_mcount)
+EXPORT_SYMBOL(_mcount)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+SYM_FUNC_START(ftrace_graph_caller)
+	MCOUNT_SAVE_REGS
+
+	PTR_ADDI	a0, ra, -4			/* arg0: Callsite self return addr */
+	PTR_ADDI	a1, sp, MCOUNT_STACK_SIZE	/* arg1: Callsite sp */
+	move	a2, s0					/* arg2: Callsite parent ra */
+	bl	prepare_ftrace_return
+
+	MCOUNT_RESTORE_REGS
+	jirl	zero, ra, 0
+SYM_FUNC_END(ftrace_graph_caller)
+
+SYM_FUNC_START(return_to_handler)
+	PTR_ADDI sp, sp, -2 * SZREG
+	PTR_S	a0, sp, 0
+	PTR_S	a1, sp, SZREG
+
+	bl	ftrace_return_to_handler
+
+	/* restore the real parent address: a0 -> ra */
+	move	ra, a0
+
+	PTR_L	a0, sp, 0
+	PTR_L	a1, sp, SZREG
+	PTR_ADDI	sp, sp, 2 * SZREG
+	jirl	zero, ra, 0
+SYM_FUNC_END(return_to_handler)
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-- 
2.36.1


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

* [PATCH 2/9] LoongArch/ftrace: Add recordmcount support
  2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
  2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
@ 2022-08-19  8:13 ` Qing Zhang
  2022-08-19  8:13 ` [PATCH 3/9] LoongArch/ftrace: Add dynamic function tracer support Qing Zhang
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

Recordmcount utility under scripts is run, after compiling each object,
to find out all the locations of calling _mcount() and put them into
specific seciton named __mcount_loc.
Then linker collects all such information into a table in the kernel image
(between __start_mcount_loc and __stop_mcount_loc) for later use by ftrace.

This patch adds loongarch specific definitions to identify such locations.
On loongarch, only C version is used to build the kernel now that
CONFIG_HAVE_C_RECORDMCOUNT is on.

Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
---
 arch/loongarch/Kconfig |  2 ++
 scripts/recordmcount.c | 23 +++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 703a2c3a8e0d..4d13bac368ed 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -80,10 +80,12 @@ config LOONGARCH
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_CONTEXT_TRACKING_USER
+	select HAVE_C_RECORDMCOUNT
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_DMA_CONTIGUOUS
 	select HAVE_EXIT_THREAD
 	select HAVE_FAST_GUP
+	select HAVE_FTRACE_MCOUNT_RECORD
         select HAVE_FUNCTION_GRAPH_TRACER
         select HAVE_FUNCTION_TRACER
 	select HAVE_GENERIC_VDSO
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index cce12e1971d8..ae42f9c5dc42 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -38,6 +38,13 @@
 #define R_AARCH64_ABS64	257
 #endif
 
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH		258
+#define R_LARCH_64		2
+#define R_LARCH_MARK_LA			20
+#define R_LARCH_SOP_PUSH_PLT_PCREL	29
+#endif
+
 #define R_ARM_PC24		1
 #define R_ARM_THM_CALL		10
 #define R_ARM_CALL		28
@@ -441,6 +448,17 @@ static int arm64_is_fake_mcount(Elf64_Rel const *rp)
 	return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26;
 }
 
+static int LARCH64_is_fake_mcount(Elf64_Rel const *rp)
+{
+	switch (ELF64_R_TYPE(w(rp->r_info))) {
+	case R_LARCH_MARK_LA:
+	case R_LARCH_SOP_PUSH_PLT_PCREL:
+		return 0;
+	}
+
+	return 1;
+}
+
 /* 64-bit EM_MIPS has weird ELF64_Rela.r_info.
  * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
  * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40]
@@ -558,6 +576,7 @@ static int do_file(char const *const fname)
 		break;
 	case EM_IA_64:	reltype = R_IA64_IMM64; break;
 	case EM_MIPS:	/* reltype: e_class    */ break;
+	case EM_LOONGARCH:	/* reltype: e_class    */ break;
 	case EM_PPC:	reltype = R_PPC_ADDR32; break;
 	case EM_PPC64:	reltype = R_PPC64_ADDR64; break;
 	case EM_S390:	/* reltype: e_class    */ break;
@@ -610,6 +629,10 @@ static int do_file(char const *const fname)
 			Elf64_r_info = MIPS64_r_info;
 			is_fake_mcount64 = MIPS64_is_fake_mcount;
 		}
+		if (w2(ghdr->e_machine) == EM_LOONGARCH) {
+			reltype = R_LARCH_64;
+			is_fake_mcount64 = LARCH64_is_fake_mcount;
+		}
 		if (do64(ghdr, fname, reltype) < 0)
 			goto out;
 		break;
-- 
2.36.1


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

* [PATCH 3/9] LoongArch/ftrace: Add dynamic function tracer support
  2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
  2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
  2022-08-19  8:13 ` [PATCH 2/9] LoongArch/ftrace: Add recordmcount support Qing Zhang
@ 2022-08-19  8:13 ` Qing Zhang
  2022-08-19  8:13 ` [PATCH 4/9] Loongarch/ftrace: Add dynamic function graph " Qing Zhang
  2022-08-19  8:13 ` [PATCH 5/9] Loongarch/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support Qing Zhang
  4 siblings, 0 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

The compiler has inserted 2 NOPs before the regular function prologue.
T series registers are available and safe because of LoongArch psABI.

At runtime, replace nop with bl to enable ftrace call and replace bl with
nop to disable ftrace call. The bl requires us to save the original RA value,
so here it saves RA at t0.
details are:

| Compiled   |       Disabled         |        Enabled         |
+------------+------------------------+------------------------+
| nop        | move     t0, ra        | move     t0, ra        |
| nop        | nop                    | bl      ftrace_caller  |
| func_body  | func_body              | func_body              |

The RA value will be recovered by ftrace_regs_entry, and restored into RA
before returning to the regular function prologue. When a function is not
being traced, the move t0, ra is not harmful.

1) ftrace_make_call, ftrace_make_nop (in kernel/ftrace.c)
   The two functions turn each recorded call site of filtered functions
   into a call to ftrace_caller or nops.

2) ftracce_update_ftrace_func (in kernel/ftrace.c)
   turns the nops at ftrace_call into a call to a generic entry for
   function tracers.

3) ftrace_caller (in kernel/mcount-dyn.S)
   The entry where each _mcount call sites calls to once they are
   filtered to be traced.

Co-developed-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
---
 arch/loongarch/Kconfig              |   1 +
 arch/loongarch/include/asm/ftrace.h |  16 ++++
 arch/loongarch/include/asm/inst.h   |  33 +++++++++
 arch/loongarch/kernel/Makefile      |   5 ++
 arch/loongarch/kernel/entry_dyn.S   |  89 ++++++++++++++++++++++
 arch/loongarch/kernel/ftrace_dyn.c  | 111 ++++++++++++++++++++++++++++
 arch/loongarch/kernel/inst.c        |  93 +++++++++++++++++++++++
 7 files changed, 348 insertions(+)
 create mode 100644 arch/loongarch/kernel/entry_dyn.S
 create mode 100644 arch/loongarch/kernel/ftrace_dyn.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 4d13bac368ed..f2d4899b1a0e 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -83,6 +83,7 @@ config LOONGARCH
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_DMA_CONTIGUOUS
+        select HAVE_DYNAMIC_FTRACE
 	select HAVE_EXIT_THREAD
 	select HAVE_FAST_GUP
 	select HAVE_FTRACE_MCOUNT_RECORD
diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
index 6a3e76234618..76ca58767f4d 100644
--- a/arch/loongarch/include/asm/ftrace.h
+++ b/arch/loongarch/include/asm/ftrace.h
@@ -10,9 +10,25 @@
 #define MCOUNT_INSN_SIZE 4		/* sizeof mcount call */
 
 #ifndef __ASSEMBLY__
+#ifndef CONFIG_DYNAMIC_FTRACE
 extern void _mcount(void);
 #define mcount _mcount
+#endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+
+struct dyn_ftrace;
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+#define ftrace_init_nop ftrace_init_nop
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 #endif /* _ASM_LOONGARCH_FTRACE_H */
diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 7b07cbb3188c..713b4996bfac 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -8,6 +8,9 @@
 #include <linux/types.h>
 #include <asm/asm.h>
 
+#define INSN_NOP 0x03400000
+#define INSN_BREAK 0x002a0000
+
 #define ADDR_IMMMASK_LU52ID	0xFFF0000000000000
 #define ADDR_IMMMASK_LU32ID	0x000FFFFF00000000
 #define ADDR_IMMMASK_ADDU16ID	0x00000000FFFF0000
@@ -18,6 +21,11 @@
 
 #define ADDR_IMM(addr, INSN)	((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
 
+enum reg0i26_op {
+	b_op		= 0x14,
+	bl_op		= 0x15,
+};
+
 enum reg1i20_op {
 	lu12iw_op	= 0x0a,
 	lu32id_op	= 0x0b,
@@ -32,6 +40,7 @@ enum reg2i12_op {
 	addiw_op	= 0x0a,
 	addid_op	= 0x0b,
 	lu52id_op	= 0x0c,
+	ori_op          = 0x0e,
 	ldb_op		= 0xa0,
 	ldh_op		= 0xa1,
 	ldw_op		= 0xa2,
@@ -52,6 +61,10 @@ enum reg2i16_op {
 	bgeu_op		= 0x1b,
 };
 
+enum reg3_op {
+	or_op		= 0x2a,
+};
+
 struct reg0i26_format {
 	unsigned int immediate_h : 10;
 	unsigned int immediate_l : 16;
@@ -85,6 +98,13 @@ struct reg2i16_format {
 	unsigned int opcode : 6;
 };
 
+struct reg3_format {
+	unsigned int rd : 5;
+	unsigned int rj : 5;
+	unsigned int rk : 5;
+	unsigned int opcode : 17;
+};
+
 union loongarch_instruction {
 	unsigned int word;
 	struct reg0i26_format reg0i26_format;
@@ -92,6 +112,7 @@ union loongarch_instruction {
 	struct reg1i21_format reg1i21_format;
 	struct reg2i12_format reg2i12_format;
 	struct reg2i16_format reg2i16_format;
+	struct reg3_format    reg3_format;
 };
 
 #define LOONGARCH_INSN_SIZE	sizeof(union loongarch_instruction)
@@ -162,6 +183,18 @@ static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
 		is_imm12_negative(ip->reg2i12_format.immediate);
 }
 
+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);
+
+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_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);
+
 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
 u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 0a745d24d3e5..a73599619466 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -15,8 +15,13 @@ obj-$(CONFIG_EFI) 		+= efi.o
 obj-$(CONFIG_CPU_HAS_FPU)	+= fpu.o
 
 ifdef CONFIG_FUNCTION_TRACER
+  ifndef CONFIG_DYNAMIC_FTRACE
     obj-y += mcount.o ftrace.o
     CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+  else
+    obj-y += entry_dyn.o ftrace_dyn.o
+    CFLAGS_REMOVE_ftrace_dyn.o = $(CC_FLAGS_FTRACE)
+  endif
   CFLAGS_REMOVE_inst.o = $(CC_FLAGS_FTRACE)
   CFLAGS_REMOVE_time.o = $(CC_FLAGS_FTRACE)
   CFLAGS_REMOVE_perf_event.o = $(CC_FLAGS_FTRACE)
diff --git a/arch/loongarch/kernel/entry_dyn.S b/arch/loongarch/kernel/entry_dyn.S
new file mode 100644
index 000000000000..e4686e67f049
--- /dev/null
+++ b/arch/loongarch/kernel/entry_dyn.S
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#include <asm/export.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/ftrace.h>
+
+	.text
+/*
+ * Due to -fpatchable-function-entry=2: the compiler inserted 2 NOPs before the
+ * regular C function prologue. When PC arrived here, the last 2 instructions
+ * as follows,
+ * 	move		t0, ra
+ * 	bl		callsite (for modules, callsite is a tramplione)
+ *
+ * modules tramplione as follows,
+ * 	addu16i.d	t1, zero, callsite[31:16]
+ * 	lu32i.d		t1, callsite[51:32]
+ * 	lu52i.d		t1, t1, callsite[63:52]
+ * 	jirl		zero, t1, callsite[15:0] >> 2
+ *
+ * See arch/loongarch/kernel/ftrace_dyn.c for details. Here, pay attention to
+ * that the T series regs are available and safe because each C functions
+ * follows the LoongArch psABI well.
+ */
+
+	.macro  ftrace_regs_entry
+	PTR_ADDI sp, sp, -PT_SIZE
+	/* Save trace function ra at PT_ERA */
+	PTR_S	ra, sp, PT_ERA
+	/* Save parent ra at PT_R1(RA) */
+	PTR_S	t0, sp, PT_R1
+	PTR_S	a0, sp, PT_R4
+	PTR_S	a1, sp, PT_R5
+	PTR_S	a2, sp, PT_R6
+	PTR_S	a3, sp, PT_R7
+	PTR_S	a4, sp, PT_R8
+	PTR_S	a5, sp, PT_R9
+	PTR_S	a6, sp, PT_R10
+	PTR_S	a7, sp, PT_R11
+	PTR_S	fp, sp, PT_R22
+
+	PTR_ADDI t8, sp, PT_SIZE
+	PTR_S   t8, sp, PT_R3
+
+	.endm
+
+SYM_CODE_START(ftrace_caller)
+	ftrace_regs_entry
+	b	ftrace_common
+SYM_CODE_END(ftrace_caller)
+
+SYM_CODE_START(ftrace_common)
+	PTR_ADDI	a0, ra, -8	/* arg0: ip */
+	move		a1, t0		/* arg1: parent_ip */
+	la.pcrel	t1, function_trace_op
+	PTR_L		a2, t1, 0	/* arg2: op */
+	move		a3, sp		/* arg3: regs */
+	.globl ftrace_call
+ftrace_call:
+	bl		ftrace_stub
+/*
+ * As we didn't use S series regs in this assmembly code and all calls
+ * are C function which will save S series regs by themselves, there is
+ * no need to restore S series regs. The T series is available and safe
+ * at the callsite, so there is no need to restore the T series regs.
+ */
+ftrace_common_return:
+	PTR_L	a0, sp, PT_R4
+	PTR_L	a1, sp, PT_R5
+	PTR_L	a2, sp, PT_R6
+	PTR_L	a3, sp, PT_R7
+	PTR_L	a4, sp, PT_R8
+	PTR_L	a5, sp, PT_R9
+	PTR_L	a6, sp, PT_R10
+	PTR_L	a7, sp, PT_R11
+	PTR_L	fp, sp, PT_R22
+	PTR_L	ra, sp, PT_R1
+	PTR_L	t0, sp, PT_ERA
+	PTR_ADDI sp, sp, PT_SIZE
+	jirl	zero, t0, 0
+SYM_CODE_END(ftrace_common)
+
+SYM_FUNC_START(ftrace_stub)
+	jirl	zero, ra, 0
+SYM_FUNC_END(ftrace_stub)
diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c
new file mode 100644
index 000000000000..1f8955be8b64
--- /dev/null
+++ b/arch/loongarch/kernel/ftrace_dyn.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Based on arch/arm64/kernel/ftrace.c
+ *
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/ftrace.h>
+#include <linux/uaccess.h>
+
+#include <asm/inst.h>
+
+static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
+			      bool validate)
+{
+	u32 replaced;
+
+	if (validate) {
+		if (larch_insn_read((void *)pc, &replaced))
+			return -EFAULT;
+
+		if (replaced != old)
+			return -EINVAL;
+	}
+
+	if (larch_insn_patch_text((void *)pc, new))
+		return -EPERM;
+
+	return 0;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+	unsigned long pc;
+	u32 new;
+
+	pc = (unsigned long)&ftrace_call;
+	new = larch_insn_gen_bl(pc, (unsigned long)func);
+
+	return ftrace_modify_code(pc, 0, new, false);
+}
+
+/*
+ * The compiler has inserted 2 NOPs before the regular function prologue.
+ * T series registers are available and safe because of LoongArch psABI.
+ *
+ * At runtime, replace nop with bl to enable ftrace call and replace bl with
+ * nop to disable ftrace call. The bl requires us to save the original RA value,
+ * so here it saves RA at t0.
+ * details are:
+ *
+ * | Compiled   |       Disabled         |        Enabled         |
+ * +------------+------------------------+------------------------+
+ * | nop        | move     t0, ra        | move     t0, ra        |
+ * | nop        | nop                    | bl      ftrace_caller  |
+ * | func_body  | func_body              | func_body              |
+ *
+ * The RA value will be recovered by ftrace_regs_entry, and restored into RA
+ * before returning to the regular function prologue. When a function is not
+ * being traced, the move t0, ra is not harmful.
+ */
+
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
+{
+	unsigned long pc;
+	u32 old, new;
+
+	pc = rec->ip;
+	old = larch_insn_gen_nop();
+	new = larch_insn_gen_move(LOONGARCH_GPR_T0, LOONGARCH_GPR_RA);
+
+	return ftrace_modify_code(pc, old, new, true);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned long pc;
+	u32 old, new;
+
+	pc = rec->ip + LOONGARCH_INSN_SIZE;
+
+	old = larch_insn_gen_nop();
+	new = larch_insn_gen_bl(pc, addr);
+
+	return ftrace_modify_code(pc, old, new, true);
+}
+
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+		    unsigned long addr)
+{
+	unsigned long pc;
+	u32 old, new;
+
+	pc = rec->ip + LOONGARCH_INSN_SIZE;
+
+	new = larch_insn_gen_nop();
+	old = larch_insn_gen_bl(pc, addr);
+
+	return ftrace_modify_code(pc, old, new, true);
+}
+
+void arch_ftrace_update_code(int command)
+{
+	command |= FTRACE_MAY_SLEEP;
+	ftrace_modify_all_code(command);
+}
+
+int __init ftrace_dyn_arch_init(void)
+{
+	return 0;
+}
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index b1df0ec34bd1..f2759ae9a8bd 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -2,8 +2,83 @@
 /*
  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  */
+#include <linux/sizes.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
 #include <asm/inst.h>
 
+static DEFINE_RAW_SPINLOCK(patch_lock);
+
+int larch_insn_read(void *addr, u32 *insnp)
+{
+	int ret;
+	u32 val;
+
+	ret = copy_from_kernel_nofault(&val, addr, LOONGARCH_INSN_SIZE);
+	if (!ret)
+		*insnp = val;
+
+	return ret;
+}
+
+int larch_insn_write(void *addr, u32 insn)
+{
+	int ret;
+	unsigned long flags = 0;
+
+	raw_spin_lock_irqsave(&patch_lock, flags);
+	ret = copy_to_kernel_nofault(addr, &insn, LOONGARCH_INSN_SIZE);
+	raw_spin_unlock_irqrestore(&patch_lock, flags);
+
+	return ret;
+}
+
+int larch_insn_patch_text(void *addr, u32 insn)
+{
+	int ret;
+	u32 *tp = addr;
+
+	if ((unsigned long)tp & 3)
+		return -EINVAL;
+
+	ret = larch_insn_write(tp, insn);
+	if (!ret)
+		flush_icache_range((unsigned long)tp,
+				   (unsigned long)tp + LOONGARCH_INSN_SIZE);
+
+	return ret;
+}
+
+u32 larch_insn_gen_nop(void)
+{
+	return INSN_NOP;
+}
+
+u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
+{
+	unsigned int immediate_l, immediate_h;
+	union loongarch_instruction insn;
+	long offset = dest - pc;
+
+	if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
+		pr_warn("The generated bl instruction is out of range.\n");
+		return INSN_BREAK;
+	}
+
+	offset >>= 2;
+
+	immediate_l = offset & 0xffff;
+	offset >>= 16;
+	immediate_h = offset & 0x3ff;
+
+	insn.reg0i26_format.opcode = bl_op;
+	insn.reg0i26_format.immediate_l = immediate_l;
+	insn.reg0i26_format.immediate_h = immediate_h;
+
+	return insn.word;
+}
+
 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
 {
 	union loongarch_instruction insn;
@@ -38,3 +113,21 @@ u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned l
 
 	return insn.word;
 }
+
+u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk)
+{
+	union loongarch_instruction insn;
+
+	insn.reg3_format.opcode = or_op;
+	insn.reg3_format.rd = rd;
+	insn.reg3_format.rj = rj;
+	insn.reg3_format.rk = rk;
+
+	return insn.word;
+}
+
+u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj)
+{
+	return larch_insn_gen_or(rd, rj, 0);
+}
+
-- 
2.36.1


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

* [PATCH 4/9] Loongarch/ftrace: Add dynamic function graph tracer support
  2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
                   ` (2 preceding siblings ...)
  2022-08-19  8:13 ` [PATCH 3/9] LoongArch/ftrace: Add dynamic function tracer support Qing Zhang
@ 2022-08-19  8:13 ` Qing Zhang
  2022-08-19  8:13 ` [PATCH 5/9] Loongarch/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support Qing Zhang
  4 siblings, 0 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

Once the function_graph tracer is enabled, a filtered function has the
following call sequence:

1) ftracer_caller        ==> on/off by ftrace_make_call/ftrace_make_nop
2) ftrace_graph_caller
3) ftrace_graph_call     ==> on/off by ftrace_en/disable_ftrace_graph_caller
4) prepare_ftrace_return

Considering the following DYNAMIC_FTRACE_WITH_REGS feature, it would be
more extendable to have a ftrace_graph_caller function, instead of
calling prepare_ftrace_return directly in ftrace_caller.

Co-developed-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
---
 arch/loongarch/kernel/entry_dyn.S  | 33 ++++++++++++++++++++++
 arch/loongarch/kernel/ftrace_dyn.c | 45 ++++++++++++++++++++++++++++++
 arch/loongarch/kernel/inst.c       | 24 ++++++++++++++++
 3 files changed, 102 insertions(+)

diff --git a/arch/loongarch/kernel/entry_dyn.S b/arch/loongarch/kernel/entry_dyn.S
index e4686e67f049..4e3fb0c9a48f 100644
--- a/arch/loongarch/kernel/entry_dyn.S
+++ b/arch/loongarch/kernel/entry_dyn.S
@@ -62,6 +62,11 @@ SYM_CODE_START(ftrace_common)
 	.globl ftrace_call
 ftrace_call:
 	bl		ftrace_stub
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	.globl ftrace_graph_call
+ftrace_graph_call:
+	nop				/* b ftrace_graph_caller */
+#endif
 /*
  * As we didn't use S series regs in this assmembly code and all calls
  * are C function which will save S series regs by themselves, there is
@@ -84,6 +89,34 @@ ftrace_common_return:
 	jirl	zero, t0, 0
 SYM_CODE_END(ftrace_common)
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+SYM_CODE_START(ftrace_graph_caller)
+	PTR_L		a0, sp, PT_ERA
+	PTR_ADDI	a0, a0, -8	/* arg0: self_addr */
+	PTR_ADDI	a1, sp, PT_R1	/* arg1: parent */
+	bl		prepare_ftrace_return
+	b		ftrace_common_return
+SYM_CODE_END(ftrace_graph_caller)
+
+SYM_CODE_START(return_to_handler)
+	/* save return value regs */
+	PTR_ADDI 	sp, sp, -2 * SZREG
+	PTR_S		a0, sp, 0
+	PTR_S		a1, sp, SZREG
+
+	move		a0, zero	/* Has no check FP now. */
+	bl		ftrace_return_to_handler
+	move		ra, a0		/* parent ra */
+
+	/* restore return value regs */
+	PTR_L		a0, sp, 0
+	PTR_L		a1, sp, SZREG
+	PTR_ADDI 	sp, sp, 2 * SZREG
+
+	jirl		zero, ra, 0
+SYM_CODE_END(return_to_handler)
+#endif
+
 SYM_FUNC_START(ftrace_stub)
 	jirl	zero, ra, 0
 SYM_FUNC_END(ftrace_stub)
diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c
index 1f8955be8b64..3fe791b6783e 100644
--- a/arch/loongarch/kernel/ftrace_dyn.c
+++ b/arch/loongarch/kernel/ftrace_dyn.c
@@ -109,3 +109,48 @@ int __init ftrace_dyn_arch_init(void)
 {
 	return 0;
 }
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+extern void ftrace_graph_call(void);
+
+void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent)
+{
+	unsigned long return_hooker = (unsigned long)&return_to_handler;
+	unsigned long old;
+
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		return;
+
+	old = *parent;
+
+	if (!function_graph_enter(old, self_addr, 0, NULL))
+		*parent = return_hooker;
+}
+
+static int ftrace_modify_graph_caller(bool enable)
+{
+	unsigned long pc, func;
+	u32 branch, nop;
+
+	pc = (unsigned long)&ftrace_graph_call;
+	func = (unsigned long)&ftrace_graph_caller;
+
+	branch = larch_insn_gen_b(pc, func);
+	nop = larch_insn_gen_nop();
+
+	if (enable)
+		return ftrace_modify_code(pc, nop, branch, true);
+	else
+		return ftrace_modify_code(pc, branch, nop, true);
+}
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+	return ftrace_modify_graph_caller(true);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+	return ftrace_modify_graph_caller(false);
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index f2759ae9a8bd..4f7a62ddf210 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -55,6 +55,30 @@ u32 larch_insn_gen_nop(void)
 	return INSN_NOP;
 }
 
+u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
+{
+	unsigned int immediate_l, immediate_h;
+	union loongarch_instruction insn;
+	long offset = dest - pc;
+
+	if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
+		pr_warn("The generated b instruction is out of range.\n");
+		return INSN_BREAK;
+	}
+
+	offset >>= 2;
+
+	immediate_l = offset & 0xffff;
+	offset >>= 16;
+	immediate_h = offset & 0x3ff;
+
+	insn.reg0i26_format.opcode = b_op;
+	insn.reg0i26_format.immediate_l = immediate_l;
+	insn.reg0i26_format.immediate_h = immediate_h;
+
+	return insn.word;
+}
+
 u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
 {
 	unsigned int immediate_l, immediate_h;
-- 
2.36.1


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

* [PATCH 5/9] Loongarch/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support
  2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
                   ` (3 preceding siblings ...)
  2022-08-19  8:13 ` [PATCH 4/9] Loongarch/ftrace: Add dynamic function graph " Qing Zhang
@ 2022-08-19  8:13 ` Qing Zhang
  4 siblings, 0 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-19  8:13 UTC (permalink / raw)
  To: Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang,
	hejinyang, zhangqing

This patch implements DYNAMIC_FTRACE_WITH_REGS on LoongArch, which allows
a traced function's arguments (and some other registers) to be captured
into a struct pt_regs, allowing these to be inspected and modified.

Co-developed-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
---
 arch/loongarch/Kconfig              |  1 +
 arch/loongarch/include/asm/ftrace.h |  3 +++
 arch/loongarch/kernel/entry_dyn.S   | 36 +++++++++++++++++++++++++++--
 arch/loongarch/kernel/ftrace_dyn.c  | 17 ++++++++++++++
 4 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index f2d4899b1a0e..22eb3d6f8537 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -84,6 +84,7 @@ config LOONGARCH
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_DMA_CONTIGUOUS
         select HAVE_DYNAMIC_FTRACE
+        select HAVE_DYNAMIC_FTRACE_WITH_REGS
 	select HAVE_EXIT_THREAD
 	select HAVE_FAST_GUP
 	select HAVE_FTRACE_MCOUNT_RECORD
diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
index 76ca58767f4d..a3f974a7a5ce 100644
--- a/arch/loongarch/include/asm/ftrace.h
+++ b/arch/loongarch/include/asm/ftrace.h
@@ -28,6 +28,9 @@ struct dyn_ftrace;
 int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
 #define ftrace_init_nop ftrace_init_nop
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+#endif
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/loongarch/kernel/entry_dyn.S b/arch/loongarch/kernel/entry_dyn.S
index 4e3fb0c9a48f..38f616c1b4db 100644
--- a/arch/loongarch/kernel/entry_dyn.S
+++ b/arch/loongarch/kernel/entry_dyn.S
@@ -27,7 +27,7 @@
  * follows the LoongArch psABI well.
  */
 
-	.macro  ftrace_regs_entry
+	.macro  ftrace_regs_entry allregs=0
 	PTR_ADDI sp, sp, -PT_SIZE
 	/* Save trace function ra at PT_ERA */
 	PTR_S	ra, sp, PT_ERA
@@ -43,16 +43,48 @@
 	PTR_S	a7, sp, PT_R11
 	PTR_S	fp, sp, PT_R22
 
+	.if \allregs
+	PTR_S	t0, sp, PT_R12
+	PTR_S	t1, sp, PT_R13
+	PTR_S	t2, sp, PT_R14
+	PTR_S	t3, sp, PT_R15
+	PTR_S	t4, sp, PT_R16
+	PTR_S	t5, sp, PT_R17
+	PTR_S	t6, sp, PT_R18
+	PTR_S	t7, sp, PT_R19
+	PTR_S	t8, sp, PT_R20
+	PTR_S	s0, sp, PT_R23
+	PTR_S	s1, sp, PT_R24
+	PTR_S	s2, sp, PT_R25
+	PTR_S	s3, sp, PT_R26
+	PTR_S	s4, sp, PT_R27
+	PTR_S	s5, sp, PT_R28
+	PTR_S	s6, sp, PT_R29
+	PTR_S	s7, sp, PT_R30
+	PTR_S	s8, sp, PT_R31
+	PTR_S	tp, sp, PT_R2
+	/* Clear it for later use as a flag sometimes. */
+	PTR_S	zero, sp, PT_R0
+	PTR_S	$r21, sp, PT_R21
+	.endif
+
 	PTR_ADDI t8, sp, PT_SIZE
 	PTR_S   t8, sp, PT_R3
 
 	.endm
 
 SYM_CODE_START(ftrace_caller)
-	ftrace_regs_entry
+	ftrace_regs_entry allregs=0
 	b	ftrace_common
 SYM_CODE_END(ftrace_caller)
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+SYM_CODE_START(ftrace_regs_caller)
+	ftrace_regs_entry allregs=1
+	b	ftrace_common
+SYM_CODE_END(ftrace_regs_caller)
+#endif
+
 SYM_CODE_START(ftrace_common)
 	PTR_ADDI	a0, ra, -8	/* arg0: ip */
 	move		a1, t0		/* arg1: parent_ip */
diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c
index 3fe791b6783e..ec3d951be50c 100644
--- a/arch/loongarch/kernel/ftrace_dyn.c
+++ b/arch/loongarch/kernel/ftrace_dyn.c
@@ -99,6 +99,23 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 	return ftrace_modify_code(pc, old, new, true);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+			unsigned long addr)
+{
+	unsigned long pc;
+	long offset;
+	u32 old, new;
+
+	pc = rec->ip + LOONGARCH_INSN_SIZE;
+
+	old = larch_insn_gen_bl(pc, old_addr);
+	new = larch_insn_gen_bl(pc, addr);
+
+	return ftrace_modify_code(pc, old, new, true);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+
 void arch_ftrace_update_code(int command)
 {
 	command |= FTRACE_MAY_SLEEP;
-- 
2.36.1


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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
@ 2022-08-19  9:29   ` Jinyang He
  2022-08-19 16:53     ` Steven Rostedt
  2022-08-19 17:25   ` Steven Rostedt
  1 sibling, 1 reply; 15+ messages in thread
From: Jinyang He @ 2022-08-19  9:29 UTC (permalink / raw)
  To: Qing Zhang, Huacai Chen, Steven Rostedt, Ingo Molnar
  Cc: WANG Xuerui, loongarch, linux-kernel, linux-arch, Jiaxun Yang

Hi, Qing

On 2022/8/19 16:13, Qing Zhang wrote:

> This patch contains basic ftrace support for LoongArch.
> Specifically, function tracer (HAVE_FUNCTION_TRACER), function graph
> tracer (HAVE_FUNCTION_GRAPH_TRACER) are implemented following the
> instructions in Documentation/trace/ftrace-design.txt.
>
> Use `-pg` makes stub like a child function `void _mcount(void *ra)`.
> Thus, it can be seen store RA and open stack before `call _mcount`.
> Find `open stack` at first, and then find `store RA`
>
> Note that the functions in both inst.c and time.c should not be
> hooked with the compiler's -pg option: to prevent infinite self-
> referencing for the former, and to ignore early setup stuff for the
> latter.
>
> Co-developed-by: Jinyang He <hejinyang@loongson.cn>
> Signed-off-by: Jinyang He <hejinyang@loongson.cn>
> Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
> ---
>   arch/loongarch/Kconfig              |  2 +
>   arch/loongarch/Makefile             |  5 ++
>   arch/loongarch/include/asm/ftrace.h | 18 ++++++
>   arch/loongarch/kernel/Makefile      |  8 +++
>   arch/loongarch/kernel/ftrace.c      | 74 +++++++++++++++++++++++
>   arch/loongarch/kernel/mcount.S      | 94 +++++++++++++++++++++++++++++
>   6 files changed, 201 insertions(+)
>   create mode 100644 arch/loongarch/include/asm/ftrace.h
>   create mode 100644 arch/loongarch/kernel/ftrace.c
>   create mode 100644 arch/loongarch/kernel/mcount.S
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 4abc9a28aba4..703a2c3a8e0d 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -84,6 +84,8 @@ config LOONGARCH
>   	select HAVE_DMA_CONTIGUOUS
>   	select HAVE_EXIT_THREAD
>   	select HAVE_FAST_GUP
> +        select HAVE_FUNCTION_GRAPH_TRACER
> +        select HAVE_FUNCTION_TRACER
>   	select HAVE_GENERIC_VDSO
>   	select HAVE_IOREMAP_PROT
>   	select HAVE_IRQ_EXIT_ON_IRQ_STACK
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index ec3de6191276..44f11a2937e9 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -29,6 +29,11 @@ ifneq ($(SUBARCH),$(ARCH))
>     endif
>   endif
>   
> +ifdef CONFIG_DYNAMIC_FTRACE
> +  KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
> +  CC_FLAGS_FTRACE := -fpatchable-function-entry=2
> +endif
> +

It seems this patch adds non-dynamic ftrace, this code should not
appear here.
BTW is it really necessary for non-dynamic ftrace? I do not use it
directly and frequently, IMHO, non-dynamic can be completely

replaced dynamic?


>   ifdef CONFIG_64BIT
>   ld-emul			= $(64bit-emul)
>   cflags-y		+= -mabi=lp64s
> diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
> new file mode 100644
> index 000000000000..6a3e76234618
> --- /dev/null
> +++ b/arch/loongarch/include/asm/ftrace.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2022 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef _ASM_LOONGARCH_FTRACE_H
> +#define _ASM_LOONGARCH_FTRACE_H
> +
> +#ifdef CONFIG_FUNCTION_TRACER
> +#define MCOUNT_INSN_SIZE 4		/* sizeof mcount call */
> +
> +#ifndef __ASSEMBLY__
> +extern void _mcount(void);
> +#define mcount _mcount
> +
> +#endif /* __ASSEMBLY__ */
> +#endif /* CONFIG_FUNCTION_TRACER */
> +#endif /* _ASM_LOONGARCH_FTRACE_H */
> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> index e5be17009fe8..0a745d24d3e5 100644
> --- a/arch/loongarch/kernel/Makefile
> +++ b/arch/loongarch/kernel/Makefile
> @@ -14,6 +14,14 @@ obj-$(CONFIG_EFI) 		+= efi.o
>   
>   obj-$(CONFIG_CPU_HAS_FPU)	+= fpu.o
>   
> +ifdef CONFIG_FUNCTION_TRACER
> +    obj-y += mcount.o ftrace.o
> +    CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
> +  CFLAGS_REMOVE_inst.o = $(CC_FLAGS_FTRACE)
> +  CFLAGS_REMOVE_time.o = $(CC_FLAGS_FTRACE)
> +  CFLAGS_REMOVE_perf_event.o = $(CC_FLAGS_FTRACE)
> +endif
> +
>   obj-$(CONFIG_MODULES)		+= module.o module-sections.o
>   obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
>   
> diff --git a/arch/loongarch/kernel/ftrace.c b/arch/loongarch/kernel/ftrace.c
> new file mode 100644
> index 000000000000..c8ddc5f11f32
> --- /dev/null
> +++ b/arch/loongarch/kernel/ftrace.c
> @@ -0,0 +1,74 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2022 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/uaccess.h>
> +#include <linux/init.h>
> +#include <linux/ftrace.h>
> +#include <linux/syscalls.h>
> +
> +#include <asm/asm.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/cacheflush.h>
> +#include <asm/inst.h>
> +#include <asm/loongarch.h>
> +#include <asm/syscall.h>
> +#include <asm/unistd.h>
> +
> +#include <asm-generic/sections.h>
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +
> +/*
> + * As `call _mcount` follows LoongArch psABI, ra-saved operation and
> + * stack operation can be found before this insn.
> + */
> +
> +static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off)
> +{
> +	union loongarch_instruction *insn;
> +	int limit = 32;
> +
> +	insn = (union loongarch_instruction *)insn_addr;
> +
> +	do {
> +		insn--;
> +		limit--;
> +
> +		if (is_ra_save_ins(insn))
> +			*ra_off = -((1 << 12) - insn->reg2i12_format.immediate);
> +
> +	} while (!is_stack_alloc_ins(insn) && limit);
> +
> +	if (!limit)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +void prepare_ftrace_return(unsigned long self_addr,
> +		unsigned long callsite_sp, unsigned long old)
> +{
> +	int ra_off;
> +	unsigned long return_hooker = (unsigned long)&return_to_handler;
> +
> +	if (unlikely(ftrace_graph_is_dead()))
> +		return;
> +
> +	if (unlikely(atomic_read(&current->tracing_graph_pause)))
> +		return;
> +
> +	if (ftrace_get_parent_ra_addr(self_addr, &ra_off))
> +		goto out;
> +
> +	if (!function_graph_enter(old, self_addr, 0, NULL))
> +		*(unsigned long *)(callsite_sp + ra_off) = return_hooker;
> +
> +	return;
> +
> +out:
> +	ftrace_graph_stop();
> +	WARN_ON(1);
> +}
> +#endif	/* CONFIG_FUNCTION_GRAPH_TRACER */
> diff --git a/arch/loongarch/kernel/mcount.S b/arch/loongarch/kernel/mcount.S
> new file mode 100644
> index 000000000000..f1c1cc1a629e
> --- /dev/null
> +++ b/arch/loongarch/kernel/mcount.S
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * LoongArch specific _mcount support
> + *
> + * Copyright (C) 2022 Loongson Technology Corporation Limited
> + */
> +
> +#include <asm/export.h>
> +#include <asm/regdef.h>
> +#include <asm/stackframe.h>
> +#include <asm/ftrace.h>
> +
> +	.text
> +
> +#define MCOUNT_STACK_SIZE	(2 * SZREG)
> +#define MCOUNT_S0_OFFSET	(0)
> +#define MCOUNT_RA_OFFSET	(SZREG)
> +
> +	.macro MCOUNT_SAVE_REGS
> +	PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
> +	PTR_S	s0, sp, MCOUNT_S0_OFFSET
> +	PTR_S	ra, sp, MCOUNT_RA_OFFSET
> +	move	s0, a0
> +	.endm
> +
> +	.macro MCOUNT_RESTORE_REGS
> +	move	a0, s0
> +	PTR_L	ra, sp, MCOUNT_RA_OFFSET
> +	PTR_L	s0, sp, MCOUNT_S0_OFFSET
> +	PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
> +	.endm
> +
> +
> +SYM_FUNC_START(_mcount)
> +	la	t1, ftrace_stub
> +	la	t2, ftrace_trace_function	/* Prepare t2 for (1) */

'la.pcrel' is preferred here while 'la' should be deprecated.


> +	PTR_L	t2, t2, 0
> +	beq	t1, t2, fgraph_trace
> +
> +	MCOUNT_SAVE_REGS
> +
> +	move	a0, ra				/* arg0: self return address */
> +	move	a1, s0				/* arg1: parent's return address */
> +	jirl	ra, t2, 0			/* (1) call *ftrace_trace_function */
> +
> +	MCOUNT_RESTORE_REGS
> +
> +fgraph_trace:
> +#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
> +	la	t1, ftrace_stub
> +	la	t3, ftrace_graph_return
> +	PTR_L	t3, t3, 0
> +	bne	t1, t3, ftrace_graph_caller
> +	la	t1, ftrace_graph_entry_stub
> +	la	t3, ftrace_graph_entry
> +	PTR_L	t3, t3, 0
> +	bne	t1, t3, ftrace_graph_caller
> +#endif
> +
> +	.globl ftrace_stub
> +ftrace_stub:
> +	jirl	zero, ra, 0
> +SYM_FUNC_END(_mcount)
> +EXPORT_SYMBOL(_mcount)
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +SYM_FUNC_START(ftrace_graph_caller)
> +	MCOUNT_SAVE_REGS
> +
> +	PTR_ADDI	a0, ra, -4			/* arg0: Callsite self return addr */
> +	PTR_ADDI	a1, sp, MCOUNT_STACK_SIZE	/* arg1: Callsite sp */
> +	move	a2, s0					/* arg2: Callsite parent ra */
> +	bl	prepare_ftrace_return
> +
> +	MCOUNT_RESTORE_REGS
> +	jirl	zero, ra, 0
We know Xuerui had done a lot works to keep asm code normalize.
So I think we should replace 'jirl zero,ra,0' with 'jr ra'. The basic

rule is use assembly macro as possible, I think.


Thanks,

Jinyang


> +SYM_FUNC_END(ftrace_graph_caller)
> +
> +SYM_FUNC_START(return_to_handler)
> +	PTR_ADDI sp, sp, -2 * SZREG
> +	PTR_S	a0, sp, 0
> +	PTR_S	a1, sp, SZREG
> +
> +	bl	ftrace_return_to_handler
> +
> +	/* restore the real parent address: a0 -> ra */
> +	move	ra, a0
> +
> +	PTR_L	a0, sp, 0
> +	PTR_L	a1, sp, SZREG
> +	PTR_ADDI	sp, sp, 2 * SZREG
> +	jirl	zero, ra, 0
> +SYM_FUNC_END(return_to_handler)
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */


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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19  9:29   ` Jinyang He
@ 2022-08-19 16:53     ` Steven Rostedt
  2022-08-20  1:34       ` Qing Zhang
  0 siblings, 1 reply; 15+ messages in thread
From: Steven Rostedt @ 2022-08-19 16:53 UTC (permalink / raw)
  To: Jinyang He
  Cc: Qing Zhang, Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch,
	linux-kernel, linux-arch, Jiaxun Yang

On Fri, 19 Aug 2022 17:29:29 +0800
Jinyang He <hejinyang@loongson.cn> wrote:

> It seems this patch adds non-dynamic ftrace, this code should not
> appear here.
> BTW is it really necessary for non-dynamic ftrace? I do not use it
> directly and frequently, IMHO, non-dynamic can be completely
> 
> replaced dynamic?

Note, I keep the non dynamic ftrace around for debugging purposes.

But sure, it's pretty useless. It's also good for bringing ftrace to a new
architecture (like this patch is doing), as it is easier to implement than
dynamic ftrace, and getting the non-dynamic working is usually the first
step in getting dynamic ftrace working.

But it's really up to the arch maintainers to keep it or not.

-- Steve

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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
  2022-08-19  9:29   ` Jinyang He
@ 2022-08-19 17:25   ` Steven Rostedt
  2022-08-20  1:35     ` Qing Zhang
  2022-08-20  1:38     ` Jinyang He
  1 sibling, 2 replies; 15+ messages in thread
From: Steven Rostedt @ 2022-08-19 17:25 UTC (permalink / raw)
  To: Qing Zhang
  Cc: Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch, linux-kernel,
	linux-arch, Jiaxun Yang, hejinyang

On Fri, 19 Aug 2022 16:13:55 +0800
Qing Zhang <zhangqing@loongson.cn> wrote:

> +#define MCOUNT_STACK_SIZE	(2 * SZREG)
> +#define MCOUNT_S0_OFFSET	(0)
> +#define MCOUNT_RA_OFFSET	(SZREG)
> +
> +	.macro MCOUNT_SAVE_REGS
> +	PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
> +	PTR_S	s0, sp, MCOUNT_S0_OFFSET
> +	PTR_S	ra, sp, MCOUNT_RA_OFFSET
> +	move	s0, a0
> +	.endm
> +
> +	.macro MCOUNT_RESTORE_REGS
> +	move	a0, s0
> +	PTR_L	ra, sp, MCOUNT_RA_OFFSET
> +	PTR_L	s0, sp, MCOUNT_S0_OFFSET
> +	PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
> +	.endm
> +
> +
> +SYM_FUNC_START(_mcount)
> +	la	t1, ftrace_stub
> +	la	t2, ftrace_trace_function	/* Prepare t2 for (1) */
> +	PTR_L	t2, t2, 0
> +	beq	t1, t2, fgraph_trace
> +
> +	MCOUNT_SAVE_REGS
> +
> +	move	a0, ra				/* arg0: self return address */
> +	move	a1, s0				/* arg1: parent's return address */
> +	jirl	ra, t2, 0			/* (1) call *ftrace_trace_function */
> +
> +	MCOUNT_RESTORE_REGS

You know, if you can implement CONFIG_FTRACE_WITH_ARGS, where the default
function callback gets a ftrace_regs pointer (that only holds what is
needed for the arguments of the function as well as the stack pointer),
then you could also implement function graph on top of that, and remove the
need for the below "fgraph_trace" trampoline.

I'd really would like all architectures to go that way. Also, the
CONFIG_FTRACE_WITH_ARGS is all you need for live kernel patching.

-- Steve


> +
> +fgraph_trace:
> +#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
> +	la	t1, ftrace_stub
> +	la	t3, ftrace_graph_return
> +	PTR_L	t3, t3, 0
> +	bne	t1, t3, ftrace_graph_caller
> +	la	t1, ftrace_graph_entry_stub
> +	la	t3, ftrace_graph_entry
> +	PTR_L	t3, t3, 0
> +	bne	t1, t3, ftrace_graph_caller
> +#endif
> +
> +	.globl ftrace_stub
> +ftrace_stub:
> +	jirl	zero, ra, 0
> +SYM_FUNC_END(_mcount)
> +EXPORT_SYMBOL(_mcount)
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +SYM_FUNC_START(ftrace_graph_caller)
> +	MCOUNT_SAVE_REGS
> +
> +	PTR_ADDI	a0, ra, -4			/* arg0: Callsite self return addr */
> +	PTR_ADDI	a1, sp, MCOUNT_STACK_SIZE	/* arg1: Callsite sp */
> +	move	a2, s0					/* arg2: Callsite parent ra */
> +	bl	prepare_ftrace_return
> +
> +	MCOUNT_RESTORE_REGS
> +	jirl	zero, ra, 0
> +SYM_FUNC_END(ftrace_graph_caller)

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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19 16:53     ` Steven Rostedt
@ 2022-08-20  1:34       ` Qing Zhang
  2022-08-20  2:16         ` Huacai Chen
  0 siblings, 1 reply; 15+ messages in thread
From: Qing Zhang @ 2022-08-20  1:34 UTC (permalink / raw)
  To: Steven Rostedt, Jinyang He
  Cc: Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch, linux-kernel,
	linux-arch, Jiaxun Yang



On 2022/8/20 上午12:53, Steven Rostedt wrote:
> On Fri, 19 Aug 2022 17:29:29 +0800
> Jinyang He <hejinyang@loongson.cn> wrote:
> 
>> It seems this patch adds non-dynamic ftrace, this code should not
>> appear here.
>> BTW is it really necessary for non-dynamic ftrace? I do not use it
>> directly and frequently, IMHO, non-dynamic can be completely
>>
>> replaced dynamic?
> 
> Note, I keep the non dynamic ftrace around for debugging purposes.
> 
> But sure, it's pretty useless. It's also good for bringing ftrace to a new
> architecture (like this patch is doing), as it is easier to implement than
> dynamic ftrace, and getting the non-dynamic working is usually the first
> step in getting dynamic ftrace working.
> 
> But it's really up to the arch maintainers to keep it or not.
>
Before submitting, I saw that other architectures almost kept 
non-dynamic methods without cleaning up, I tend to keep them.
How do you think, Huacai. :)

Thanks,
- Qing
> -- Steve
> 


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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19 17:25   ` Steven Rostedt
@ 2022-08-20  1:35     ` Qing Zhang
  2022-08-20  1:38     ` Jinyang He
  1 sibling, 0 replies; 15+ messages in thread
From: Qing Zhang @ 2022-08-20  1:35 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch, linux-kernel,
	linux-arch, Jiaxun Yang, hejinyang



On 2022/8/20 上午1:25, Steven Rostedt wrote:
> On Fri, 19 Aug 2022 16:13:55 +0800
> Qing Zhang <zhangqing@loongson.cn> wrote:
> 
>> +#define MCOUNT_STACK_SIZE	(2 * SZREG)
>> +#define MCOUNT_S0_OFFSET	(0)
>> +#define MCOUNT_RA_OFFSET	(SZREG)
>> +
>> +	.macro MCOUNT_SAVE_REGS
>> +	PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
>> +	PTR_S	s0, sp, MCOUNT_S0_OFFSET
>> +	PTR_S	ra, sp, MCOUNT_RA_OFFSET
>> +	move	s0, a0
>> +	.endm
>> +
>> +	.macro MCOUNT_RESTORE_REGS
>> +	move	a0, s0
>> +	PTR_L	ra, sp, MCOUNT_RA_OFFSET
>> +	PTR_L	s0, sp, MCOUNT_S0_OFFSET
>> +	PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
>> +	.endm
>> +
>> +
>> +SYM_FUNC_START(_mcount)
>> +	la	t1, ftrace_stub
>> +	la	t2, ftrace_trace_function	/* Prepare t2 for (1) */
>> +	PTR_L	t2, t2, 0
>> +	beq	t1, t2, fgraph_trace
>> +
>> +	MCOUNT_SAVE_REGS
>> +
>> +	move	a0, ra				/* arg0: self return address */
>> +	move	a1, s0				/* arg1: parent's return address */
>> +	jirl	ra, t2, 0			/* (1) call *ftrace_trace_function */
>> +
>> +	MCOUNT_RESTORE_REGS
> 
> You know, if you can implement CONFIG_FTRACE_WITH_ARGS, where the default
> function callback gets a ftrace_regs pointer (that only holds what is
> needed for the arguments of the function as well as the stack pointer),
> then you could also implement function graph on top of that, and remove the
> need for the below "fgraph_trace" trampoline.
> 
> I'd really would like all architectures to go that way. Also, the
> CONFIG_FTRACE_WITH_ARGS is all you need for live kernel patching.
> 
Hi, Steve
I will add the implementation of CONFIG_FTRACE_WITH_ARGS in v2.

Thanks,
- Qing
> -- Steve
> 
> 
>> +
>> +fgraph_trace:
>> +#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
>> +	la	t1, ftrace_stub
>> +	la	t3, ftrace_graph_return
>> +	PTR_L	t3, t3, 0
>> +	bne	t1, t3, ftrace_graph_caller
>> +	la	t1, ftrace_graph_entry_stub
>> +	la	t3, ftrace_graph_entry
>> +	PTR_L	t3, t3, 0
>> +	bne	t1, t3, ftrace_graph_caller
>> +#endif
>> +
>> +	.globl ftrace_stub
>> +ftrace_stub:
>> +	jirl	zero, ra, 0
>> +SYM_FUNC_END(_mcount)
>> +EXPORT_SYMBOL(_mcount)
>> +
>> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
>> +SYM_FUNC_START(ftrace_graph_caller)
>> +	MCOUNT_SAVE_REGS
>> +
>> +	PTR_ADDI	a0, ra, -4			/* arg0: Callsite self return addr */
>> +	PTR_ADDI	a1, sp, MCOUNT_STACK_SIZE	/* arg1: Callsite sp */
>> +	move	a2, s0					/* arg2: Callsite parent ra */
>> +	bl	prepare_ftrace_return
>> +
>> +	MCOUNT_RESTORE_REGS
>> +	jirl	zero, ra, 0
>> +SYM_FUNC_END(ftrace_graph_caller)


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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-19 17:25   ` Steven Rostedt
  2022-08-20  1:35     ` Qing Zhang
@ 2022-08-20  1:38     ` Jinyang He
  2022-08-20  1:52       ` Steven Rostedt
  1 sibling, 1 reply; 15+ messages in thread
From: Jinyang He @ 2022-08-20  1:38 UTC (permalink / raw)
  To: Steven Rostedt, Qing Zhang
  Cc: Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch, linux-kernel,
	linux-arch, Jiaxun Yang

On 08/20/2022 01:25 AM, Steven Rostedt wrote:

> On Fri, 19 Aug 2022 16:13:55 +0800
> Qing Zhang <zhangqing@loongson.cn> wrote:
>
>> +#define MCOUNT_STACK_SIZE	(2 * SZREG)
>> +#define MCOUNT_S0_OFFSET	(0)
>> +#define MCOUNT_RA_OFFSET	(SZREG)
>> +
>> +	.macro MCOUNT_SAVE_REGS
>> +	PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
>> +	PTR_S	s0, sp, MCOUNT_S0_OFFSET
>> +	PTR_S	ra, sp, MCOUNT_RA_OFFSET
>> +	move	s0, a0
>> +	.endm
>> +
>> +	.macro MCOUNT_RESTORE_REGS
>> +	move	a0, s0
>> +	PTR_L	ra, sp, MCOUNT_RA_OFFSET
>> +	PTR_L	s0, sp, MCOUNT_S0_OFFSET
>> +	PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
>> +	.endm
>> +
>> +
>> +SYM_FUNC_START(_mcount)
>> +	la	t1, ftrace_stub
>> +	la	t2, ftrace_trace_function	/* Prepare t2 for (1) */
>> +	PTR_L	t2, t2, 0
>> +	beq	t1, t2, fgraph_trace
>> +
>> +	MCOUNT_SAVE_REGS
>> +
>> +	move	a0, ra				/* arg0: self return address */
>> +	move	a1, s0				/* arg1: parent's return address */
>> +	jirl	ra, t2, 0			/* (1) call *ftrace_trace_function */
>> +
>> +	MCOUNT_RESTORE_REGS
> You know, if you can implement CONFIG_FTRACE_WITH_ARGS, where the default
> function callback gets a ftrace_regs pointer (that only holds what is
> needed for the arguments of the function as well as the stack pointer),
> then you could also implement function graph on top of that, and remove the
> need for the below "fgraph_trace" trampoline.
>
> I'd really would like all architectures to go that way. Also, the
> CONFIG_FTRACE_WITH_ARGS is all you need for live kernel patching.
Hi, Steve,

I think we have implemented CONFIG_FTRACE_WITH_ARGS in dynamic ftrace
in the [Patch3/9]. But, for non dynamic ftrace, it is hardly to
implement it. Because the LoongArch compiler gcc treats mount as a
really call, like 'call _mcount(__builtin_return_address(0))'. That
means, they decrease stack, save args to callee saved regs and may
do some optimization before calling mcount. It is difficult to find the
original args and apply changes from tracers.

Thanks,
Jinyang

>
>
>> +
>> +fgraph_trace:
>> +#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
>> +	la	t1, ftrace_stub
>> +	la	t3, ftrace_graph_return
>> +	PTR_L	t3, t3, 0
>> +	bne	t1, t3, ftrace_graph_caller
>> +	la	t1, ftrace_graph_entry_stub
>> +	la	t3, ftrace_graph_entry
>> +	PTR_L	t3, t3, 0
>> +	bne	t1, t3, ftrace_graph_caller
>> +#endif
>> +
>> +	.globl ftrace_stub
>> +ftrace_stub:
>> +	jirl	zero, ra, 0
>> +SYM_FUNC_END(_mcount)
>> +EXPORT_SYMBOL(_mcount)
>> +
>> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
>> +SYM_FUNC_START(ftrace_graph_caller)
>> +	MCOUNT_SAVE_REGS
>> +
>> +	PTR_ADDI	a0, ra, -4			/* arg0: Callsite self return addr */
>> +	PTR_ADDI	a1, sp, MCOUNT_STACK_SIZE	/* arg1: Callsite sp */
>> +	move	a2, s0					/* arg2: Callsite parent ra */
>> +	bl	prepare_ftrace_return
>> +
>> +	MCOUNT_RESTORE_REGS
>> +	jirl	zero, ra, 0
>> +SYM_FUNC_END(ftrace_graph_caller)


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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-20  1:38     ` Jinyang He
@ 2022-08-20  1:52       ` Steven Rostedt
  2022-08-20  3:16         ` Jinyang He
  0 siblings, 1 reply; 15+ messages in thread
From: Steven Rostedt @ 2022-08-20  1:52 UTC (permalink / raw)
  To: Jinyang He
  Cc: Qing Zhang, Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch,
	linux-kernel, linux-arch, Jiaxun Yang

On Sat, 20 Aug 2022 09:38:21 +0800
Jinyang He <hejinyang@loongson.cn> wrote:

> I think we have implemented CONFIG_FTRACE_WITH_ARGS in dynamic ftrace
> in the [Patch3/9]. 

Sorry, I must have missed it.

> But, for non dynamic ftrace, it is hardly to
> implement it. Because the LoongArch compiler gcc treats mount as a

Don't bother implementing it for non-dynamic. I would just add a:

config HAVE_FTRACE_WITH_ARGS if DYNAMIC_FTRACE

and be done with it.

> really call, like 'call _mcount(__builtin_return_address(0))'. That
> means, they decrease stack, save args to callee saved regs and may
> do some optimization before calling mcount. It is difficult to find the
> original args and apply changes from tracers.

Right, there's no point in implementing it for non dynamic. Like I said,
non-dynamic is just a stepping stone for getting dynamic working. Once you
have dynamic working, it's up to you to throw out the non-dynamic. It's not
useful for anything other than porting to a new architecture or for
academic purposes.

-- Steve

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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-20  1:34       ` Qing Zhang
@ 2022-08-20  2:16         ` Huacai Chen
  0 siblings, 0 replies; 15+ messages in thread
From: Huacai Chen @ 2022-08-20  2:16 UTC (permalink / raw)
  To: Qing Zhang
  Cc: Steven Rostedt, Jinyang He, Ingo Molnar, WANG Xuerui, loongarch,
	LKML, linux-arch, Jiaxun Yang

Hi, all,

On Sat, Aug 20, 2022 at 9:34 AM Qing Zhang <zhangqing@loongson.cn> wrote:
>
>
>
> On 2022/8/20 上午12:53, Steven Rostedt wrote:
> > On Fri, 19 Aug 2022 17:29:29 +0800
> > Jinyang He <hejinyang@loongson.cn> wrote:
> >
> >> It seems this patch adds non-dynamic ftrace, this code should not
> >> appear here.
> >> BTW is it really necessary for non-dynamic ftrace? I do not use it
> >> directly and frequently, IMHO, non-dynamic can be completely
> >>
> >> replaced dynamic?
> >
> > Note, I keep the non dynamic ftrace around for debugging purposes.
> >
> > But sure, it's pretty useless. It's also good for bringing ftrace to a new
> > architecture (like this patch is doing), as it is easier to implement than
> > dynamic ftrace, and getting the non-dynamic working is usually the first
> > step in getting dynamic ftrace working.
> >
> > But it's really up to the arch maintainers to keep it or not.
> >
> Before submitting, I saw that other architectures almost kept
> non-dynamic methods without cleaning up, I tend to keep them.
> How do you think, Huacai. :)
I prefer to keep the non-dynamic method.

Huacai
>
> Thanks,
> - Qing
> > -- Steve
> >
>
>

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

* Re: [PATCH 1/9] LoongArch/ftrace: Add basic support
  2022-08-20  1:52       ` Steven Rostedt
@ 2022-08-20  3:16         ` Jinyang He
  0 siblings, 0 replies; 15+ messages in thread
From: Jinyang He @ 2022-08-20  3:16 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Qing Zhang, Huacai Chen, Ingo Molnar, WANG Xuerui, loongarch,
	linux-kernel, linux-arch, Jiaxun Yang

On 08/20/2022 09:52 AM, Steven Rostedt wrote:

> On Sat, 20 Aug 2022 09:38:21 +0800
> Jinyang He <hejinyang@loongson.cn> wrote:
>
>> I think we have implemented CONFIG_FTRACE_WITH_ARGS in dynamic ftrace
>> in the [Patch3/9].
> Sorry, I must have missed it.
And there is still something left to do, Qing will do that.

>
>> But, for non dynamic ftrace, it is hardly to
>> implement it. Because the LoongArch compiler gcc treats mount as a
> Don't bother implementing it for non-dynamic. I would just add a:
>
> config HAVE_FTRACE_WITH_ARGS if DYNAMIC_FTRACE
>
> and be done with it.
Yes, it is clear.

>
>> really call, like 'call _mcount(__builtin_return_address(0))'. That
>> means, they decrease stack, save args to callee saved regs and may
>> do some optimization before calling mcount. It is difficult to find the
>> original args and apply changes from tracers.
> Right, there's no point in implementing it for non dynamic. Like I said,
> non-dynamic is just a stepping stone for getting dynamic working. Once you
> have dynamic working, it's up to you to throw out the non-dynamic. It's not
> useful for anything other than porting to a new architecture or for
> academic purposes.
>
Thanks for your detail answers.
Jinyang


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

end of thread, other threads:[~2022-08-20  3:16 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-19  8:13 [PATCH 0/9] LoongArch: Add ftrace support Qing Zhang
2022-08-19  8:13 ` [PATCH 1/9] LoongArch/ftrace: Add basic support Qing Zhang
2022-08-19  9:29   ` Jinyang He
2022-08-19 16:53     ` Steven Rostedt
2022-08-20  1:34       ` Qing Zhang
2022-08-20  2:16         ` Huacai Chen
2022-08-19 17:25   ` Steven Rostedt
2022-08-20  1:35     ` Qing Zhang
2022-08-20  1:38     ` Jinyang He
2022-08-20  1:52       ` Steven Rostedt
2022-08-20  3:16         ` Jinyang He
2022-08-19  8:13 ` [PATCH 2/9] LoongArch/ftrace: Add recordmcount support Qing Zhang
2022-08-19  8:13 ` [PATCH 3/9] LoongArch/ftrace: Add dynamic function tracer support Qing Zhang
2022-08-19  8:13 ` [PATCH 4/9] Loongarch/ftrace: Add dynamic function graph " Qing Zhang
2022-08-19  8:13 ` [PATCH 5/9] Loongarch/ftrace: Add DYNAMIC_FTRACE_WITH_REGS support Qing Zhang

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.