xref: /linux/arch/arm64/include/asm/ftrace.h (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1d2912cb1SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2819e50e2SAKASHI Takahiro /*
3819e50e2SAKASHI Takahiro  * arch/arm64/include/asm/ftrace.h
4819e50e2SAKASHI Takahiro  *
5819e50e2SAKASHI Takahiro  * Copyright (C) 2013 Linaro Limited
6819e50e2SAKASHI Takahiro  * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7819e50e2SAKASHI Takahiro  */
8819e50e2SAKASHI Takahiro #ifndef __ASM_FTRACE_H
9819e50e2SAKASHI Takahiro #define __ASM_FTRACE_H
10819e50e2SAKASHI Takahiro 
11819e50e2SAKASHI Takahiro #include <asm/insn.h>
12819e50e2SAKASHI Takahiro 
135c176affSMark Rutland #define HAVE_FUNCTION_GRAPH_FP_TEST
143b23e499STorsten Duwe 
1526299b3fSMark Rutland #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
163b23e499STorsten Duwe #define ARCH_SUPPORTS_FTRACE_OPS 1
173b23e499STorsten Duwe #else
18607289a7SSami Tolvanen #define MCOUNT_ADDR		((unsigned long)_mcount)
193b23e499STorsten Duwe #endif
203b23e499STorsten Duwe 
213b23e499STorsten Duwe /* The BL at the callsite's adjusted rec->ip */
22819e50e2SAKASHI Takahiro #define MCOUNT_INSN_SIZE	AARCH64_INSN_SIZE
23819e50e2SAKASHI Takahiro 
243b23e499STorsten Duwe #define FTRACE_PLT_IDX		0
2526299b3fSMark Rutland #define NR_FTRACE_PLTS		1
263b23e499STorsten Duwe 
27f7edb451SSteven Rostedt (VMware) /*
28f7edb451SSteven Rostedt (VMware)  * Currently, gcc tends to save the link register after the local variables
29f7edb451SSteven Rostedt (VMware)  * on the stack. This causes the max stack tracer to report the function
30f7edb451SSteven Rostedt (VMware)  * frame sizes for the wrong functions. By defining
31f7edb451SSteven Rostedt (VMware)  * ARCH_FTRACE_SHIFT_STACK_TRACER, it will tell the stack tracer to expect
32f7edb451SSteven Rostedt (VMware)  * to find the return address on the stack after the local variables have
33f7edb451SSteven Rostedt (VMware)  * been set up.
34f7edb451SSteven Rostedt (VMware)  *
35f7edb451SSteven Rostedt (VMware)  * Note, this may change in the future, and we will need to deal with that
36f7edb451SSteven Rostedt (VMware)  * if it were to happen.
37f7edb451SSteven Rostedt (VMware)  */
38f7edb451SSteven Rostedt (VMware) #define ARCH_FTRACE_SHIFT_STACK_TRACER 1
39f7edb451SSteven Rostedt (VMware) 
40819e50e2SAKASHI Takahiro #ifndef __ASSEMBLY__
41055b1212SAKASHI Takahiro #include <linux/compat.h>
42055b1212SAKASHI Takahiro 
43819e50e2SAKASHI Takahiro extern void _mcount(unsigned long);
443711784eSAKASHI Takahiro extern void *return_address(unsigned int);
45bd7d38dbSAKASHI Takahiro 
46bd7d38dbSAKASHI Takahiro struct dyn_arch_ftrace {
47bd7d38dbSAKASHI Takahiro 	/* No extra data needed for arm64 */
48bd7d38dbSAKASHI Takahiro };
49bd7d38dbSAKASHI Takahiro 
50bd7d38dbSAKASHI Takahiro extern unsigned long ftrace_graph_call;
51bd7d38dbSAKASHI Takahiro 
5220380bb3SAKASHI Takahiro extern void return_to_handler(void);
5320380bb3SAKASHI Takahiro 
54baaf553dSMark Rutland unsigned long ftrace_call_adjust(unsigned long addr);
553711784eSAKASHI Takahiro 
5626299b3fSMark Rutland #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
573b23e499STorsten Duwe struct dyn_ftrace;
58c4a0ebf8SChengming Zhou struct ftrace_ops;
5926299b3fSMark Rutland 
6026299b3fSMark Rutland #define arch_ftrace_get_regs(regs) NULL
6126299b3fSMark Rutland 
622aa6ac03SFlorent Revest /*
632aa6ac03SFlorent Revest  * Note: sizeof(struct ftrace_regs) must be a multiple of 16 to ensure correct
642aa6ac03SFlorent Revest  * stack alignment
652aa6ac03SFlorent Revest  */
6626299b3fSMark Rutland struct ftrace_regs {
6726299b3fSMark Rutland 	/* x0 - x8 */
6826299b3fSMark Rutland 	unsigned long regs[9];
692aa6ac03SFlorent Revest 
702aa6ac03SFlorent Revest #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
712aa6ac03SFlorent Revest 	unsigned long direct_tramp;
722aa6ac03SFlorent Revest #else
7326299b3fSMark Rutland 	unsigned long __unused;
742aa6ac03SFlorent Revest #endif
7526299b3fSMark Rutland 
7626299b3fSMark Rutland 	unsigned long fp;
7726299b3fSMark Rutland 	unsigned long lr;
7826299b3fSMark Rutland 
7926299b3fSMark Rutland 	unsigned long sp;
8026299b3fSMark Rutland 	unsigned long pc;
8126299b3fSMark Rutland };
8226299b3fSMark Rutland 
8326299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_instruction_pointer(const struct ftrace_regs * fregs)8426299b3fSMark Rutland ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs)
8526299b3fSMark Rutland {
8626299b3fSMark Rutland 	return fregs->pc;
8726299b3fSMark Rutland }
8826299b3fSMark Rutland 
8926299b3fSMark Rutland static __always_inline void
ftrace_regs_set_instruction_pointer(struct ftrace_regs * fregs,unsigned long pc)9026299b3fSMark Rutland ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
9126299b3fSMark Rutland 				    unsigned long pc)
9226299b3fSMark Rutland {
9326299b3fSMark Rutland 	fregs->pc = pc;
9426299b3fSMark Rutland }
9526299b3fSMark Rutland 
9626299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_stack_pointer(const struct ftrace_regs * fregs)9726299b3fSMark Rutland ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
9826299b3fSMark Rutland {
9926299b3fSMark Rutland 	return fregs->sp;
10026299b3fSMark Rutland }
10126299b3fSMark Rutland 
10226299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_argument(struct ftrace_regs * fregs,unsigned int n)10326299b3fSMark Rutland ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n)
10426299b3fSMark Rutland {
10526299b3fSMark Rutland 	if (n < 8)
10626299b3fSMark Rutland 		return fregs->regs[n];
10726299b3fSMark Rutland 	return 0;
10826299b3fSMark Rutland }
10926299b3fSMark Rutland 
11026299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_return_value(const struct ftrace_regs * fregs)11126299b3fSMark Rutland ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
11226299b3fSMark Rutland {
11326299b3fSMark Rutland 	return fregs->regs[0];
11426299b3fSMark Rutland }
11526299b3fSMark Rutland 
11626299b3fSMark Rutland static __always_inline void
ftrace_regs_set_return_value(struct ftrace_regs * fregs,unsigned long ret)11726299b3fSMark Rutland ftrace_regs_set_return_value(struct ftrace_regs *fregs,
11826299b3fSMark Rutland 			     unsigned long ret)
11926299b3fSMark Rutland {
12026299b3fSMark Rutland 	fregs->regs[0] = ret;
12126299b3fSMark Rutland }
12226299b3fSMark Rutland 
12326299b3fSMark Rutland static __always_inline void
ftrace_override_function_with_return(struct ftrace_regs * fregs)12426299b3fSMark Rutland ftrace_override_function_with_return(struct ftrace_regs *fregs)
12526299b3fSMark Rutland {
12626299b3fSMark Rutland 	fregs->pc = fregs->lr;
12726299b3fSMark Rutland }
12826299b3fSMark Rutland 
12926299b3fSMark Rutland int ftrace_regs_query_register_offset(const char *name);
130c4a0ebf8SChengming Zhou 
1313b23e499STorsten Duwe int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
1323b23e499STorsten Duwe #define ftrace_init_nop ftrace_init_nop
133c4a0ebf8SChengming Zhou 
134c4a0ebf8SChengming Zhou void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
135c4a0ebf8SChengming Zhou 		       struct ftrace_ops *op, struct ftrace_regs *fregs);
136c4a0ebf8SChengming Zhou #define ftrace_graph_func ftrace_graph_func
1372aa6ac03SFlorent Revest 
1382aa6ac03SFlorent Revest #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
arch_ftrace_set_direct_caller(struct ftrace_regs * fregs,unsigned long addr)1392aa6ac03SFlorent Revest static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
1402aa6ac03SFlorent Revest 						 unsigned long addr)
1412aa6ac03SFlorent Revest {
1422aa6ac03SFlorent Revest 	/*
1432aa6ac03SFlorent Revest 	 * The ftrace trampoline will return to this address instead of the
1442aa6ac03SFlorent Revest 	 * instrumented function.
1452aa6ac03SFlorent Revest 	 */
1462aa6ac03SFlorent Revest 	fregs->direct_tramp = addr;
1472aa6ac03SFlorent Revest }
1482aa6ac03SFlorent Revest #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
1492aa6ac03SFlorent Revest 
1503b23e499STorsten Duwe #endif
1513b23e499STorsten Duwe 
1523711784eSAKASHI Takahiro #define ftrace_return_address(n) return_address(n)
153055b1212SAKASHI Takahiro 
154055b1212SAKASHI Takahiro /*
155055b1212SAKASHI Takahiro  * Because AArch32 mode does not share the same syscall table with AArch64,
156055b1212SAKASHI Takahiro  * tracing compat syscalls may result in reporting bogus syscalls or even
157055b1212SAKASHI Takahiro  * hang-up, so just do not trace them.
158055b1212SAKASHI Takahiro  * See kernel/trace/trace_syscalls.c
159055b1212SAKASHI Takahiro  *
160055b1212SAKASHI Takahiro  * x86 code says:
161ef769e32SAdam Buchbinder  * If the user really wants these, then they should use the
162055b1212SAKASHI Takahiro  * raw syscall tracepoints with filtering.
163055b1212SAKASHI Takahiro  */
164055b1212SAKASHI Takahiro #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
arch_trace_is_compat_syscall(struct pt_regs * regs)165055b1212SAKASHI Takahiro static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
166055b1212SAKASHI Takahiro {
167055b1212SAKASHI Takahiro 	return is_compat_task();
168055b1212SAKASHI Takahiro }
169874bfc6eSMasami Hiramatsu 
170874bfc6eSMasami Hiramatsu #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
171874bfc6eSMasami Hiramatsu 
arch_syscall_match_sym_name(const char * sym,const char * name)172874bfc6eSMasami Hiramatsu static inline bool arch_syscall_match_sym_name(const char *sym,
173874bfc6eSMasami Hiramatsu 					       const char *name)
174874bfc6eSMasami Hiramatsu {
175874bfc6eSMasami Hiramatsu 	/*
176874bfc6eSMasami Hiramatsu 	 * Since all syscall functions have __arm64_ prefix, we must skip it.
177874bfc6eSMasami Hiramatsu 	 * However, as we described above, we decided to ignore compat
178874bfc6eSMasami Hiramatsu 	 * syscalls, so we don't care about __arm64_compat_ prefix here.
179874bfc6eSMasami Hiramatsu 	 */
180874bfc6eSMasami Hiramatsu 	return !strcmp(sym + 8, name);
181874bfc6eSMasami Hiramatsu }
1823711784eSAKASHI Takahiro #endif /* ifndef __ASSEMBLY__ */
183819e50e2SAKASHI Takahiro 
18436469703SDonglin Peng #ifndef __ASSEMBLY__
18536469703SDonglin Peng #ifdef CONFIG_FUNCTION_GRAPH_TRACER
18636469703SDonglin Peng struct fgraph_ret_regs {
18736469703SDonglin Peng 	/* x0 - x7 */
18836469703SDonglin Peng 	unsigned long regs[8];
18936469703SDonglin Peng 
19036469703SDonglin Peng 	unsigned long fp;
19136469703SDonglin Peng 	unsigned long __unused;
19236469703SDonglin Peng };
19336469703SDonglin Peng 
fgraph_ret_regs_return_value(struct fgraph_ret_regs * ret_regs)19436469703SDonglin Peng static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
19536469703SDonglin Peng {
19636469703SDonglin Peng 	return ret_regs->regs[0];
19736469703SDonglin Peng }
19836469703SDonglin Peng 
fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs * ret_regs)19936469703SDonglin Peng static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
20036469703SDonglin Peng {
20136469703SDonglin Peng 	return ret_regs->fp;
20236469703SDonglin Peng }
203*7d8b31b7SArnd Bergmann 
204*7d8b31b7SArnd Bergmann void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
205*7d8b31b7SArnd Bergmann 			   unsigned long frame_pointer);
206*7d8b31b7SArnd Bergmann 
20736469703SDonglin Peng #endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER  */
20836469703SDonglin Peng #endif
20936469703SDonglin Peng 
210819e50e2SAKASHI Takahiro #endif /* __ASM_FTRACE_H */
211