Skip to content

Commit dbe3ba3

Browse files
zhangqingmychenhuacai
authored andcommitted
LoongArch/ftrace: Add basic support
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 alloc stack before `call _mcount`. Find `alloc 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 <[email protected]> Signed-off-by: Jinyang He <[email protected]> Signed-off-by: Qing Zhang <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 9151dde commit dbe3ba3

File tree

5 files changed

+200
-0
lines changed

5 files changed

+200
-0
lines changed

arch/loongarch/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ config LOONGARCH
9090
select HAVE_EBPF_JIT
9191
select HAVE_EXIT_THREAD
9292
select HAVE_FAST_GUP
93+
select HAVE_FUNCTION_GRAPH_TRACER
94+
select HAVE_FUNCTION_TRACER
9395
select HAVE_GENERIC_VDSO
9496
select HAVE_IOREMAP_PROT
9597
select HAVE_IRQ_EXIT_ON_IRQ_STACK

arch/loongarch/include/asm/ftrace.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2022 Loongson Technology Corporation Limited
4+
*/
5+
6+
#ifndef _ASM_LOONGARCH_FTRACE_H
7+
#define _ASM_LOONGARCH_FTRACE_H
8+
9+
#ifdef CONFIG_FUNCTION_TRACER
10+
11+
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */
12+
13+
#ifndef __ASSEMBLY__
14+
#define mcount _mcount
15+
extern void _mcount(void);
16+
extern void prepare_ftrace_return(unsigned long self_addr, unsigned long callsite_sp, unsigned long old);
17+
#endif /* __ASSEMBLY__ */
18+
19+
#endif /* CONFIG_FUNCTION_TRACER */
20+
21+
#endif /* _ASM_LOONGARCH_FTRACE_H */

arch/loongarch/kernel/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ obj-$(CONFIG_EFI) += efi.o
1515

1616
obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
1717

18+
ifdef CONFIG_FUNCTION_TRACER
19+
obj-y += mcount.o ftrace.o
20+
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
21+
CFLAGS_REMOVE_inst.o = $(CC_FLAGS_FTRACE)
22+
CFLAGS_REMOVE_time.o = $(CC_FLAGS_FTRACE)
23+
CFLAGS_REMOVE_perf_event.o = $(CC_FLAGS_FTRACE)
24+
endif
25+
1826
obj-$(CONFIG_MODULES) += module.o module-sections.o
1927
obj-$(CONFIG_STACKTRACE) += stacktrace.o
2028

arch/loongarch/kernel/ftrace.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2022 Loongson Technology Corporation Limited
4+
*/
5+
6+
#include <linux/init.h>
7+
#include <linux/ftrace.h>
8+
#include <linux/syscalls.h>
9+
#include <linux/uaccess.h>
10+
11+
#include <asm/asm.h>
12+
#include <asm/asm-offsets.h>
13+
#include <asm/cacheflush.h>
14+
#include <asm/inst.h>
15+
#include <asm/loongarch.h>
16+
#include <asm/syscall.h>
17+
18+
#include <asm-generic/sections.h>
19+
20+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
21+
22+
/*
23+
* As `call _mcount` follows LoongArch psABI, ra-saved operation and
24+
* stack operation can be found before this insn.
25+
*/
26+
27+
static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off)
28+
{
29+
int limit = 32;
30+
union loongarch_instruction *insn;
31+
32+
insn = (union loongarch_instruction *)insn_addr;
33+
34+
do {
35+
insn--;
36+
limit--;
37+
38+
if (is_ra_save_ins(insn))
39+
*ra_off = -((1 << 12) - insn->reg2i12_format.immediate);
40+
41+
} while (!is_stack_alloc_ins(insn) && limit);
42+
43+
if (!limit)
44+
return -EINVAL;
45+
46+
return 0;
47+
}
48+
49+
void prepare_ftrace_return(unsigned long self_addr,
50+
unsigned long callsite_sp, unsigned long old)
51+
{
52+
int ra_off;
53+
unsigned long return_hooker = (unsigned long)&return_to_handler;
54+
55+
if (unlikely(ftrace_graph_is_dead()))
56+
return;
57+
58+
if (unlikely(atomic_read(&current->tracing_graph_pause)))
59+
return;
60+
61+
if (ftrace_get_parent_ra_addr(self_addr, &ra_off))
62+
goto out;
63+
64+
if (!function_graph_enter(old, self_addr, 0, NULL))
65+
*(unsigned long *)(callsite_sp + ra_off) = return_hooker;
66+
67+
return;
68+
69+
out:
70+
ftrace_graph_stop();
71+
WARN_ON(1);
72+
}
73+
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

arch/loongarch/kernel/mcount.S

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* LoongArch specific _mcount support
4+
*
5+
* Copyright (C) 2022 Loongson Technology Corporation Limited
6+
*/
7+
8+
#include <asm/export.h>
9+
#include <asm/ftrace.h>
10+
#include <asm/regdef.h>
11+
#include <asm/stackframe.h>
12+
13+
.text
14+
15+
#define MCOUNT_S0_OFFSET (0)
16+
#define MCOUNT_RA_OFFSET (SZREG)
17+
#define MCOUNT_STACK_SIZE (2 * SZREG)
18+
19+
.macro MCOUNT_SAVE_REGS
20+
PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE
21+
PTR_S s0, sp, MCOUNT_S0_OFFSET
22+
PTR_S ra, sp, MCOUNT_RA_OFFSET
23+
move s0, a0
24+
.endm
25+
26+
.macro MCOUNT_RESTORE_REGS
27+
move a0, s0
28+
PTR_L ra, sp, MCOUNT_RA_OFFSET
29+
PTR_L s0, sp, MCOUNT_S0_OFFSET
30+
PTR_ADDI sp, sp, MCOUNT_STACK_SIZE
31+
.endm
32+
33+
SYM_FUNC_START(_mcount)
34+
la.pcrel t1, ftrace_stub
35+
la.pcrel t2, ftrace_trace_function /* Prepare t2 for (1) */
36+
PTR_L t2, t2, 0
37+
beq t1, t2, fgraph_trace
38+
39+
MCOUNT_SAVE_REGS
40+
41+
move a0, ra /* arg0: self return address */
42+
move a1, s0 /* arg1: parent's return address */
43+
jirl ra, t2, 0 /* (1) call *ftrace_trace_function */
44+
45+
MCOUNT_RESTORE_REGS
46+
47+
fgraph_trace:
48+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
49+
la.pcrel t1, ftrace_stub
50+
la.pcrel t3, ftrace_graph_return
51+
PTR_L t3, t3, 0
52+
bne t1, t3, ftrace_graph_caller
53+
la.pcrel t1, ftrace_graph_entry_stub
54+
la.pcrel t3, ftrace_graph_entry
55+
PTR_L t3, t3, 0
56+
bne t1, t3, ftrace_graph_caller
57+
#endif
58+
59+
SYM_INNER_LABEL(ftrace_stub, SYM_L_GLOBAL)
60+
jr ra
61+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
62+
SYM_INNER_LABEL(ftrace_graph_func, SYM_L_GLOBAL)
63+
bl ftrace_stub
64+
#endif
65+
SYM_FUNC_END(_mcount)
66+
EXPORT_SYMBOL(_mcount)
67+
68+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
69+
SYM_FUNC_START(ftrace_graph_caller)
70+
MCOUNT_SAVE_REGS
71+
72+
PTR_ADDI a0, ra, -4 /* arg0: Callsite self return addr */
73+
PTR_ADDI a1, sp, MCOUNT_STACK_SIZE /* arg1: Callsite sp */
74+
move a2, s0 /* arg2: Callsite parent ra */
75+
bl prepare_ftrace_return
76+
77+
MCOUNT_RESTORE_REGS
78+
jr ra
79+
SYM_FUNC_END(ftrace_graph_caller)
80+
81+
SYM_FUNC_START(return_to_handler)
82+
PTR_ADDI sp, sp, -2 * SZREG
83+
PTR_S a0, sp, 0
84+
PTR_S a1, sp, SZREG
85+
86+
bl ftrace_return_to_handler
87+
88+
/* Restore the real parent address: a0 -> ra */
89+
move ra, a0
90+
91+
PTR_L a0, sp, 0
92+
PTR_L a1, sp, SZREG
93+
PTR_ADDI sp, sp, 2 * SZREG
94+
jr ra
95+
SYM_FUNC_END(return_to_handler)
96+
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

0 commit comments

Comments
 (0)