Skip to contentSkip to conversation

Support ftrace on NDS32 architecture

PATCH In review Zong Li 3 participants 9 messages Aug 15, 2018 – Aug 21, 2018 ftrace

lore
Share & tools
lore

Zong Li

author
#0 lore raw

cover Support ftrace on NDS32 architecture

This patch set implements the ftrace function and function graph tracer on NDS32 architecture. We try to use C code to do everything, so we don't need to separate the implementation to assembly code and C code, we just need one ftrace.c file.

In mcount function, we use the prologue/epilogue which generated by compiler to help us to save/restore the status. On the other hand, we use naked attribute of gcc to avoid to generate the prologue/epilogue when we don't need it(such as ftrace_stub and return_to_handler).

We pass the following tests:

1. FTRACE_STARTUP_TEST: PASS

2. tools/testing/selftests/ftrace/:

 # of passed:  28
 # of failed:  1
 # of unresolved:  0
 # of untested:  0
 # of unsupported:  38
 # of xfailed:  0
 # of undefined(test bug):  0

The failed case is func-filter-glob.tc.
When setting the '*aw*lock' to the set_ftrace_filter in this test case, we got the error because we have no these functions such as _raw_spin_lock, _raw_spin_trylock and so on in our kernel.

Zong Li (6):
nds32/ftrace: Support static function tracer nds32/ftrace: Support static function graph tracer nds32/ftrace: Add RECORD_MCOUNT support
nds32/ftrace: Support dynamic function tracer nds32/ftrace: Support dynamic function graph tracer nds32/stack: Get real return address by using ftrace_graph_ret_addr

 arch/nds32/Kconfig              |   4 +
 arch/nds32/Makefile             |   4 +
 arch/nds32/include/asm/ftrace.h |  46 +++++++
 arch/nds32/kernel/Makefile      |   6 +
 arch/nds32/kernel/ftrace.c      | 297 ++++++++++++++++++++++++++++++++++++++++
 arch/nds32/kernel/stacktrace.c  |   4 +
 arch/nds32/kernel/traps.c       |  30 +---
 scripts/recordmcount.pl         |   3 +
 8 files changed, 370 insertions(+), 24 deletions(-)
 create mode 100644 arch/nds32/include/asm/ftrace.h
 create mode 100644 arch/nds32/kernel/ftrace.c
Signature · 1 line
2.7.4
author
#1 lore raw

PATCH 1/6 nds32/ftrace: Support static function tracer

This patch support the static function tracer. On nds32 ABI, we need to always push return address to stack for __builtin_return_address can work correctly, otherwise, it will get the wrong value of $lp at leaf function.

---
 arch/nds32/Kconfig              |  1 +
 arch/nds32/Makefile             |  4 ++++
 arch/nds32/include/asm/ftrace.h | 20 ++++++++++++++++++++
 arch/nds32/kernel/Makefile      |  6 ++++++
 arch/nds32/kernel/ftrace.c      | 28 ++++++++++++++++++++++++++++
 5 files changed, 59 insertions(+)
 create mode 100644 arch/nds32/include/asm/ftrace.h
 create mode 100644 arch/nds32/kernel/ftrace.c
arch/nds32/Kconfig +1 -0
index 34f7222..af30e1a 100644
@@ -40,6 +40,7 @@ config NDS32
 	select NO_IOPORT_MAP
 	select RTC_LIB
 	select THREAD_INFO_IN_TASK
+	select HAVE_FUNCTION_TRACER
 	help
 	  Andes(nds32) Linux support.
 
arch/nds32/Makefile +4 -0
index 031c676..3ca8172 100644
@@ -5,6 +5,10 @@ KBUILD_DEFCONFIG := defconfig
 
 comma = ,
 
+ifdef CONFIG_FUNCTION_TRACER
+arch-y += -malways-save-lp -mno-relax
+endif
+
 KBUILD_CFLAGS	+= $(call cc-option, -mno-sched-prolog-epilog)
 KBUILD_CFLAGS	+= -mcmodel=large
 
arch/nds32/include/asm/ftrace.h new file +20 -0
new file mode 100644
index 0000000..bac7657
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_NDS32_FTRACE_H
+#define __ASM_NDS32_FTRACE_H
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define HAVE_FUNCTION_GRAPH_FP_TEST
+
+#define MCOUNT_ADDR ((unsigned long)(_mcount))
+/* mcount call is composed of three instructions:
+ * sethi + ori + jral
+ */
+#define MCOUNT_INSN_SIZE 12
+
+extern void _mcount(unsigned long parent_ip);
+
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#endif /* __ASM_NDS32_FTRACE_H */
arch/nds32/kernel/Makefile +6 -0
index 4279274..27cded3 100644
@@ -21,3 +21,9 @@ extra-y := head.o vmlinux.lds
 
 
 obj-y				+= vdso/
+
+obj-$(CONFIG_FUNCTION_TRACER)   += ftrace.o
+
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+endif
arch/nds32/kernel/ftrace.c new file +28 -0
new file mode 100644
index 0000000..563f64c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/ftrace.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+
+extern void (*ftrace_trace_function)(unsigned long, unsigned long,
+				     struct ftrace_ops*, struct pt_regs*);
+
+noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
+				  struct ftrace_ops *op, struct pt_regs *regs)
+{
+	__asm__ ("");  /* avoid to optimize as pure function */
+}
+
+noinline void _mcount(unsigned long parent_ip)
+{
+	/* save all state by the compiler prologue */
+
+	unsigned long ip = (unsigned long)__builtin_return_address(0);
+
+	if (ftrace_trace_function != ftrace_stub)
+		ftrace_trace_function(ip - MCOUNT_INSN_SIZE, parent_ip,
+				      NULL, NULL);
+
+	/* restore all state by the compiler epilogue */
+}
+EXPORT_SYMBOL(_mcount);
Signature · 1 line
2.7.4
maintainer
#2 lore raw

Re: [PATCH 1/6] nds32/ftrace: Support static function tracer

Quoted 96 lines · On Wed, 15 Aug 2018 17:35:18 +0800 Zong Li <[email protected]> wrote:

This patch support the static function tracer. On nds32 ABI, we need to always push return address to stack for __builtin_return_address can work correctly, otherwise, it will get the wrong value of $lp at leaf function.

---
 arch/nds32/Kconfig              |  1 +
 arch/nds32/Makefile             |  4 ++++
 arch/nds32/include/asm/ftrace.h | 20 ++++++++++++++++++++
 arch/nds32/kernel/Makefile      |  6 ++++++
 arch/nds32/kernel/ftrace.c      | 28 ++++++++++++++++++++++++++++
 5 files changed, 59 insertions(+)
 create mode 100644 arch/nds32/include/asm/ftrace.h
 create mode 100644 arch/nds32/kernel/ftrace.c
arch/nds32/Kconfig +1 -0
index 34f7222..af30e1a 100644
@@ -40,6 +40,7 @@ config NDS32
 	select NO_IOPORT_MAP
 	select RTC_LIB
 	select THREAD_INFO_IN_TASK
+	select HAVE_FUNCTION_TRACER
 	help
 	  Andes(nds32) Linux support.
 
arch/nds32/Makefile +4 -0
index 031c676..3ca8172 100644
@@ -5,6 +5,10 @@ KBUILD_DEFCONFIG := defconfig
 
 comma = ,
 
+ifdef CONFIG_FUNCTION_TRACER
+arch-y += -malways-save-lp -mno-relax
+endif
+
 KBUILD_CFLAGS	+= $(call cc-option, -mno-sched-prolog-epilog)
 KBUILD_CFLAGS	+= -mcmodel=large
 
arch/nds32/include/asm/ftrace.h new file +20 -0
new file mode 100644
index 0000000..bac7657
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_NDS32_FTRACE_H
+#define __ASM_NDS32_FTRACE_H
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define HAVE_FUNCTION_GRAPH_FP_TEST
+
+#define MCOUNT_ADDR ((unsigned long)(_mcount))
+/* mcount call is composed of three instructions:
+ * sethi + ori + jral
+ */
+#define MCOUNT_INSN_SIZE 12
+
+extern void _mcount(unsigned long parent_ip);
+
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#endif /* __ASM_NDS32_FTRACE_H */
arch/nds32/kernel/Makefile +6 -0
index 4279274..27cded3 100644
@@ -21,3 +21,9 @@ extra-y := head.o vmlinux.lds
 
 
 obj-y				+= vdso/
+
+obj-$(CONFIG_FUNCTION_TRACER)   += ftrace.o
+
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+endif
arch/nds32/kernel/ftrace.c new file +7 -0
new file mode 100644
index 0000000..563f64c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/ftrace.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+
+extern void (*ftrace_trace_function)(unsigned long, unsigned long,

arch/nds32/kernel/ftrace.c line 17

Quoted 10 lines
arch/nds32/kernel/ftrace.c new file +10 -0
+				     struct ftrace_ops*, struct pt_regs*);
+
+noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
+				  struct ftrace_ops *op, struct pt_regs *regs)
+{
+	__asm__ ("");  /* avoid to optimize as pure function */
+}
+
+noinline void _mcount(unsigned long parent_ip)
+{

Wow! The NDS32 arch allows for _mcount to be a C function! That's nice :-)

-- Steve

Quoted 11 lines
arch/nds32/kernel/ftrace.c new file +11 -0
+	/* save all state by the compiler prologue */
+
+	unsigned long ip = (unsigned long)__builtin_return_address(0);
+
+	if (ftrace_trace_function != ftrace_stub)
+		ftrace_trace_function(ip - MCOUNT_INSN_SIZE, parent_ip,
+				      NULL, NULL);
+
+	/* restore all state by the compiler epilogue */
+}
+EXPORT_SYMBOL(_mcount);
author
#3 lore raw

PATCH 2/6 nds32/ftrace: Support static function graph tracer

In reply to Zong Li

This patch contains implementation of static function graph tracer.

---
 arch/nds32/Kconfig         |  1 +
 arch/nds32/kernel/ftrace.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
arch/nds32/Kconfig +1 -0
index af30e1a..ae1a94ca 100644
@@ -41,6 +41,7 @@ config NDS32
 	select RTC_LIB
 	select THREAD_INFO_IN_TASK
 	select HAVE_FUNCTION_TRACER
+	select HAVE_FUNCTION_GRAPH_TRACER
 	help
 	  Andes(nds32) Linux support.
 
arch/nds32/kernel/ftrace.c +69 -0

81 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#4 lore raw

PATCH 3/6 nds32/ftrace: Add RECORD_MCOUNT support

In reply to Zong Li

Recognize NDS32 object files in recordmcount.pl.

---
 arch/nds32/Kconfig      | 1 +
 scripts/recordmcount.pl | 3 +++
 2 files changed, 4 insertions(+)
arch/nds32/Kconfig +1 -0
index ae1a94ca..66d507d 100644
@@ -42,6 +42,7 @@ config NDS32
 	select THREAD_INFO_IN_TASK
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
+	select HAVE_FTRACE_MCOUNT_RECORD
 	help
 	  Andes(nds32) Linux support.
 
scripts/recordmcount.pl +3 -0
index fe06e77..f599031 100755
@@ -389,6 +389,9 @@ if ($arch eq "x86_64") {
     $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$";
     $type = ".quad";
     $alignment = 2;
+} elsif ($arch eq "nds32") {
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$";
+    $alignment = 2;
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
Signature · 1 line
2.7.4
author
#5 lore raw

PATCH 4/6 nds32/ftrace: Support dynamic function tracer

In reply to Zong Li

This patch contains the implementation of dynamic function tracer. The mcount call is composed of three instructions, so there are three nop for enough placeholder.

---
 arch/nds32/Kconfig              |   1 +
 arch/nds32/include/asm/ftrace.h |  26 +++++++
 arch/nds32/kernel/ftrace.c      | 164 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 191 insertions(+)
arch/nds32/Kconfig +1 -0
index 66d507d..9db36c2 100644
@@ -43,6 +43,7 @@ config NDS32
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_DYNAMIC_FTRACE
 	help
 	  Andes(nds32) Linux support.
 
arch/nds32/include/asm/ftrace.h +26 -0
index bac7657..2f96cc9 100644
@@ -15,6 +15,32 @@
 
 extern void _mcount(unsigned long parent_ip);
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+#define FTRACE_ADDR ((unsigned long)_ftrace_caller)
+
+#ifdef __NDS32_EL__
+#define INSN_NOP		0x09000040
+#define INSN_SIZE(insn)		(((insn & 0x00000080) == 0) ? 4 : 2)
+#define IS_SETHI(insn)		((insn & 0x000000fe) == 0x00000046)
+#define ENDIAN_CONVERT(insn)	be32_to_cpu(insn)
+#else /* __NDS32_EB__ */
+#define INSN_NOP		0x40000009
+#define INSN_SIZE(insn)		(((insn & 0x80000000) == 0) ? 4 : 2)
+#define IS_SETHI(insn)		((insn & 0xfe000000) == 0x46000000)
+#define ENDIAN_CONVERT(insn)	(insn)
+#endif
+
+extern void _ftrace_caller(unsigned long parent_ip);
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr;
+}
+struct dyn_arch_ftrace {
+};
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #endif /* __ASM_NDS32_FTRACE_H */
arch/nds32/kernel/ftrace.c +164 -0

180 lines not on this page · raw message

Signature · 1 line
2.7.4
author
#6 lore raw

PATCH 5/6 nds32/ftrace: Support dynamic function graph tracer

In reply to Zong Li

This patch contains the implementation of dynamic function graph tracer.

---
 arch/nds32/kernel/ftrace.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
arch/nds32/kernel/ftrace.c +36 -0
index 3ca676b..a646a83 100644
@@ -74,6 +74,14 @@ void _ftrace_caller(unsigned long parent_ip)
 		"nop			\n\t"
 		"nop			\n\t");
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	/* a placeholder for the call to ftrace_graph_caller */
+	__asm__ __volatile__ (
+		"ftrace_graph_call:	\n\t"
+		"nop			\n\t"
+		"nop			\n\t"
+		"nop			\n\t");
+#endif
 	/* restore all state needed by the compiler epilogue */
 }
 
@@ -258,4 +266,32 @@ void __naked return_to_handler(void)
 		"lmw.bim $r0,[$sp],$r1,#0x0  \n\t");
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern unsigned long ftrace_graph_call;
+
+static int ftrace_modify_graph_caller(bool enable)
+{
+	unsigned long pc = (unsigned long)&ftrace_graph_call;
+	unsigned long nop_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP};
+	unsigned long call_insn[3] = {INSN_NOP, INSN_NOP, INSN_NOP};
+
+	ftrace_gen_call_insn(call_insn, (unsigned long)ftrace_graph_caller);
+
+	if (enable)
+		return ftrace_modify_code(pc, nop_insn, call_insn, true);
+	else
+		return ftrace_modify_code(pc, call_insn, nop_insn, 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_DYNAMIC_FTRACE */
+
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
Signature · 1 line
2.7.4
author
#7 lore raw

PATCH 6/6 nds32/stack: Get real return address by using ftrace_graph_ret_addr

In reply to Zong Li

Function graph tracer has modified the return address to 'return_to_handler' on stack, and provide the 'ftrace_graph_ret_addr' to get the real return address.

---
 arch/nds32/kernel/stacktrace.c |  4 ++++
 arch/nds32/kernel/traps.c      | 30 ++++++------------------------
 2 files changed, 10 insertions(+), 24 deletions(-)
arch/nds32/kernel/stacktrace.c +4 -0
index 8b231e9..36bc870 100644
@@ -4,6 +4,7 @@
 #include <linux/sched/debug.h>
 #include <linux/sched/task_stack.h>
 #include <linux/stacktrace.h>
+#include <linux/ftrace.h>
 
 void save_stack_trace(struct stack_trace *trace)
 {
@@ -16,6 +17,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
 	unsigned long *fpn;
 	int skip = trace->skip;
 	int savesched;
+	int graph_idx = 0;
 
 	if (tsk == current) {
 		__asm__ __volatile__("\tori\t%0, $fp, #0\n":"=r"(fpn));
@@ -33,6 +35,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
 		fpp = fpn[FP_OFFSET];
 		if (!__kernel_text_address(lpp))
 			break;
+		else
+			lpp = ftrace_graph_ret_addr(tsk, &graph_idx, lpp, NULL);
 
 		if (savesched || !in_sched_functions(lpp)) {
 			if (skip) {
arch/nds32/kernel/traps.c +6 -24
index f0e9743..7684c8f 100644
@@ -8,6 +8,7 @@
 #include <linux/kdebug.h>
 #include <linux/sched/task_stack.h>
 #include <linux/uaccess.h>
+#include <linux/ftrace.h>
 
 #include <asm/proc-fns.h>
 #include <asm/unistd.h>
@@ -94,28 +95,6 @@ static void dump_instr(struct pt_regs *regs)
 	set_fs(fs);
 }
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-#include <linux/ftrace.h>
-static void
-get_real_ret_addr(unsigned long *addr, struct task_struct *tsk, int *graph)
-{
-	if (*addr == (unsigned long)return_to_handler) {
-		int index = tsk->curr_ret_stack;
-
-		if (tsk->ret_stack && index >= *graph) {
-			index -= *graph;
-			*addr = tsk->ret_stack[index].ret;
-			(*graph)++;
-		}
-	}
-}
-#else
-static inline void
-get_real_ret_addr(unsigned long *addr, struct task_struct *tsk, int *graph)
-{
-}
-#endif
-
 #define LOOP_TIMES (100)
 static void __dump(struct task_struct *tsk, unsigned long *base_reg)
 {
@@ -126,7 +105,8 @@ static void __dump(struct task_struct *tsk, unsigned long *base_reg)
 		while (!kstack_end(base_reg)) {
 			ret_addr = *base_reg++;
 			if (__kernel_text_address(ret_addr)) {
-				get_real_ret_addr(&ret_addr, tsk, &graph);
+				ret_addr = ftrace_graph_ret_addr(
+						tsk, &graph, ret_addr, NULL);
 				print_ip_sym(ret_addr);
 			}
 			if (--cnt < 0)
@@ -145,7 +125,9 @@ static void __dump(struct task_struct *tsk, unsigned long *base_reg)
 			next_fp = base_reg[FP_OFFSET];
 #endif
 			if (__kernel_text_address(ret_addr)) {
-				get_real_ret_addr(&ret_addr, tsk, &graph);
+
+				ret_addr = ftrace_graph_ret_addr(
+						tsk, &graph, ret_addr, NULL);
 				print_ip_sym(ret_addr);
 			}
 			if (--cnt < 0)
Signature · 1 line
2.7.4
Acked-by on the v1 series
#8 lore raw
In reply to Zong Li

Zong Li <[email protected]> 於 2018年8月15日 週三 下午5:35寫道:

Quoted 37 lines

This patch set implements the ftrace function and function graph tracer on NDS32 architecture. We try to use C code to do everything, so we don't need to separate the implementation to assembly code and C code, we just need one ftrace.c file.

In mcount function, we use the prologue/epilogue which generated by compiler to help us to save/restore the status. On the other hand, we use naked attribute of gcc to avoid to generate the prologue/epilogue when we don't need it(such as ftrace_stub and return_to_handler).

We pass the following tests:

1. FTRACE_STARTUP_TEST: PASS

2. tools/testing/selftests/ftrace/:

 # of passed:  28
 # of failed:  1
 # of unresolved:  0
 # of untested:  0
 # of unsupported:  38
 # of xfailed:  0
 # of undefined(test bug):  0

The failed case is func-filter-glob.tc.
When setting the '*aw*lock' to the set_ftrace_filter in this test case, we got the error because we have no these functions such as _raw_spin_lock, _raw_spin_trylock and so on in our kernel.

Zong Li (6):
nds32/ftrace: Support static function tracer nds32/ftrace: Support static function graph tracer nds32/ftrace: Add RECORD_MCOUNT support
nds32/ftrace: Support dynamic function tracer nds32/ftrace: Support dynamic function graph tracer nds32/stack: Get real return address by using ftrace_graph_ret_addr

Quoted 11 lines
 arch/nds32/Kconfig              |   4 +
 arch/nds32/Makefile             |   4 +
 arch/nds32/include/asm/ftrace.h |  46 +++++++
 arch/nds32/kernel/Makefile      |   6 +
 arch/nds32/kernel/ftrace.c      | 297 ++++++++++++++++++++++++++++++++++++++++
 arch/nds32/kernel/stacktrace.c  |   4 +
 arch/nds32/kernel/traps.c       |  30 +---
 scripts/recordmcount.pl         |   3 +
 8 files changed, 370 insertions(+), 24 deletions(-)
 create mode 100644 arch/nds32/include/asm/ftrace.h
 create mode 100644 arch/nds32/kernel/ftrace.c