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