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
15c6d3cd32SMark Rutland /*
16c6d3cd32SMark Rutland * HAVE_FUNCTION_GRAPH_RET_ADDR_PTR means that the architecture can provide a
17c6d3cd32SMark Rutland * "return address pointer" which can be used to uniquely identify a return
18c6d3cd32SMark Rutland * address which has been overwritten.
19c6d3cd32SMark Rutland *
20c6d3cd32SMark Rutland * On arm64 we use the address of the caller's frame record, which remains the
21c6d3cd32SMark Rutland * same for the lifetime of the instrumented function, unlike the return
22c6d3cd32SMark Rutland * address in the LR.
23c6d3cd32SMark Rutland */
24c6d3cd32SMark Rutland #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
25c6d3cd32SMark Rutland
2626299b3fSMark Rutland #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
273b23e499STorsten Duwe #define ARCH_SUPPORTS_FTRACE_OPS 1
283b23e499STorsten Duwe #else
29607289a7SSami Tolvanen #define MCOUNT_ADDR ((unsigned long)_mcount)
303b23e499STorsten Duwe #endif
313b23e499STorsten Duwe
323b23e499STorsten Duwe /* The BL at the callsite's adjusted rec->ip */
33819e50e2SAKASHI Takahiro #define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
34819e50e2SAKASHI Takahiro
353b23e499STorsten Duwe #define FTRACE_PLT_IDX 0
3626299b3fSMark Rutland #define NR_FTRACE_PLTS 1
373b23e499STorsten Duwe
38f7edb451SSteven Rostedt (VMware) /*
39f7edb451SSteven Rostedt (VMware) * Currently, gcc tends to save the link register after the local variables
40f7edb451SSteven Rostedt (VMware) * on the stack. This causes the max stack tracer to report the function
41f7edb451SSteven Rostedt (VMware) * frame sizes for the wrong functions. By defining
42f7edb451SSteven Rostedt (VMware) * ARCH_FTRACE_SHIFT_STACK_TRACER, it will tell the stack tracer to expect
43f7edb451SSteven Rostedt (VMware) * to find the return address on the stack after the local variables have
44f7edb451SSteven Rostedt (VMware) * been set up.
45f7edb451SSteven Rostedt (VMware) *
46f7edb451SSteven Rostedt (VMware) * Note, this may change in the future, and we will need to deal with that
47f7edb451SSteven Rostedt (VMware) * if it were to happen.
48f7edb451SSteven Rostedt (VMware) */
49f7edb451SSteven Rostedt (VMware) #define ARCH_FTRACE_SHIFT_STACK_TRACER 1
50f7edb451SSteven Rostedt (VMware)
51819e50e2SAKASHI Takahiro #ifndef __ASSEMBLY__
52055b1212SAKASHI Takahiro #include <linux/compat.h>
53055b1212SAKASHI Takahiro
54819e50e2SAKASHI Takahiro extern void _mcount(unsigned long);
553711784eSAKASHI Takahiro extern void *return_address(unsigned int);
56bd7d38dbSAKASHI Takahiro
57bd7d38dbSAKASHI Takahiro struct dyn_arch_ftrace {
58bd7d38dbSAKASHI Takahiro /* No extra data needed for arm64 */
59bd7d38dbSAKASHI Takahiro };
60bd7d38dbSAKASHI Takahiro
61bd7d38dbSAKASHI Takahiro extern unsigned long ftrace_graph_call;
62bd7d38dbSAKASHI Takahiro
6320380bb3SAKASHI Takahiro extern void return_to_handler(void);
6420380bb3SAKASHI Takahiro
65baaf553dSMark Rutland unsigned long ftrace_call_adjust(unsigned long addr);
663711784eSAKASHI Takahiro
6726299b3fSMark Rutland #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
683b23e499STorsten Duwe struct dyn_ftrace;
69c4a0ebf8SChengming Zhou struct ftrace_ops;
7026299b3fSMark Rutland
7126299b3fSMark Rutland #define arch_ftrace_get_regs(regs) NULL
7226299b3fSMark Rutland
732aa6ac03SFlorent Revest /*
742aa6ac03SFlorent Revest * Note: sizeof(struct ftrace_regs) must be a multiple of 16 to ensure correct
752aa6ac03SFlorent Revest * stack alignment
762aa6ac03SFlorent Revest */
7726299b3fSMark Rutland struct ftrace_regs {
7826299b3fSMark Rutland /* x0 - x8 */
7926299b3fSMark Rutland unsigned long regs[9];
802aa6ac03SFlorent Revest
812aa6ac03SFlorent Revest #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
822aa6ac03SFlorent Revest unsigned long direct_tramp;
832aa6ac03SFlorent Revest #else
8426299b3fSMark Rutland unsigned long __unused;
852aa6ac03SFlorent Revest #endif
8626299b3fSMark Rutland
8726299b3fSMark Rutland unsigned long fp;
8826299b3fSMark Rutland unsigned long lr;
8926299b3fSMark Rutland
9026299b3fSMark Rutland unsigned long sp;
9126299b3fSMark Rutland unsigned long pc;
9226299b3fSMark Rutland };
9326299b3fSMark Rutland
9426299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_instruction_pointer(const struct ftrace_regs * fregs)9526299b3fSMark Rutland ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs)
9626299b3fSMark Rutland {
9726299b3fSMark Rutland return fregs->pc;
9826299b3fSMark Rutland }
9926299b3fSMark Rutland
10026299b3fSMark Rutland static __always_inline void
ftrace_regs_set_instruction_pointer(struct ftrace_regs * fregs,unsigned long pc)10126299b3fSMark Rutland ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
10226299b3fSMark Rutland unsigned long pc)
10326299b3fSMark Rutland {
10426299b3fSMark Rutland fregs->pc = pc;
10526299b3fSMark Rutland }
10626299b3fSMark Rutland
10726299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_stack_pointer(const struct ftrace_regs * fregs)10826299b3fSMark Rutland ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
10926299b3fSMark Rutland {
11026299b3fSMark Rutland return fregs->sp;
11126299b3fSMark Rutland }
11226299b3fSMark Rutland
11326299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_argument(struct ftrace_regs * fregs,unsigned int n)11426299b3fSMark Rutland ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n)
11526299b3fSMark Rutland {
11626299b3fSMark Rutland if (n < 8)
11726299b3fSMark Rutland return fregs->regs[n];
11826299b3fSMark Rutland return 0;
11926299b3fSMark Rutland }
12026299b3fSMark Rutland
12126299b3fSMark Rutland static __always_inline unsigned long
ftrace_regs_get_return_value(const struct ftrace_regs * fregs)12226299b3fSMark Rutland ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
12326299b3fSMark Rutland {
12426299b3fSMark Rutland return fregs->regs[0];
12526299b3fSMark Rutland }
12626299b3fSMark Rutland
12726299b3fSMark Rutland static __always_inline void
ftrace_regs_set_return_value(struct ftrace_regs * fregs,unsigned long ret)12826299b3fSMark Rutland ftrace_regs_set_return_value(struct ftrace_regs *fregs,
12926299b3fSMark Rutland unsigned long ret)
13026299b3fSMark Rutland {
13126299b3fSMark Rutland fregs->regs[0] = ret;
13226299b3fSMark Rutland }
13326299b3fSMark Rutland
13426299b3fSMark Rutland static __always_inline void
ftrace_override_function_with_return(struct ftrace_regs * fregs)13526299b3fSMark Rutland ftrace_override_function_with_return(struct ftrace_regs *fregs)
13626299b3fSMark Rutland {
13726299b3fSMark Rutland fregs->pc = fregs->lr;
13826299b3fSMark Rutland }
13926299b3fSMark Rutland
14026299b3fSMark Rutland int ftrace_regs_query_register_offset(const char *name);
141c4a0ebf8SChengming Zhou
1423b23e499STorsten Duwe int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
1433b23e499STorsten Duwe #define ftrace_init_nop ftrace_init_nop
144c4a0ebf8SChengming Zhou
145c4a0ebf8SChengming Zhou void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
146c4a0ebf8SChengming Zhou struct ftrace_ops *op, struct ftrace_regs *fregs);
147c4a0ebf8SChengming Zhou #define ftrace_graph_func ftrace_graph_func
1482aa6ac03SFlorent Revest
1492aa6ac03SFlorent Revest #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
arch_ftrace_set_direct_caller(struct ftrace_regs * fregs,unsigned long addr)1502aa6ac03SFlorent Revest static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
1512aa6ac03SFlorent Revest unsigned long addr)
1522aa6ac03SFlorent Revest {
1532aa6ac03SFlorent Revest /*
1542aa6ac03SFlorent Revest * The ftrace trampoline will return to this address instead of the
1552aa6ac03SFlorent Revest * instrumented function.
1562aa6ac03SFlorent Revest */
1572aa6ac03SFlorent Revest fregs->direct_tramp = addr;
1582aa6ac03SFlorent Revest }
1592aa6ac03SFlorent Revest #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
1602aa6ac03SFlorent Revest
1613b23e499STorsten Duwe #endif
1623b23e499STorsten Duwe
1633711784eSAKASHI Takahiro #define ftrace_return_address(n) return_address(n)
164055b1212SAKASHI Takahiro
165055b1212SAKASHI Takahiro /*
166055b1212SAKASHI Takahiro * Because AArch32 mode does not share the same syscall table with AArch64,
167055b1212SAKASHI Takahiro * tracing compat syscalls may result in reporting bogus syscalls or even
168055b1212SAKASHI Takahiro * hang-up, so just do not trace them.
169055b1212SAKASHI Takahiro * See kernel/trace/trace_syscalls.c
170055b1212SAKASHI Takahiro *
171055b1212SAKASHI Takahiro * x86 code says:
172ef769e32SAdam Buchbinder * If the user really wants these, then they should use the
173055b1212SAKASHI Takahiro * raw syscall tracepoints with filtering.
174055b1212SAKASHI Takahiro */
175055b1212SAKASHI Takahiro #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
arch_trace_is_compat_syscall(struct pt_regs * regs)176055b1212SAKASHI Takahiro static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
177055b1212SAKASHI Takahiro {
178055b1212SAKASHI Takahiro return is_compat_task();
179055b1212SAKASHI Takahiro }
180874bfc6eSMasami Hiramatsu
181874bfc6eSMasami Hiramatsu #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
182874bfc6eSMasami Hiramatsu
arch_syscall_match_sym_name(const char * sym,const char * name)183874bfc6eSMasami Hiramatsu static inline bool arch_syscall_match_sym_name(const char *sym,
184874bfc6eSMasami Hiramatsu const char *name)
185874bfc6eSMasami Hiramatsu {
186874bfc6eSMasami Hiramatsu /*
187874bfc6eSMasami Hiramatsu * Since all syscall functions have __arm64_ prefix, we must skip it.
188874bfc6eSMasami Hiramatsu * However, as we described above, we decided to ignore compat
189874bfc6eSMasami Hiramatsu * syscalls, so we don't care about __arm64_compat_ prefix here.
190874bfc6eSMasami Hiramatsu */
191874bfc6eSMasami Hiramatsu return !strcmp(sym + 8, name);
192874bfc6eSMasami Hiramatsu }
1933711784eSAKASHI Takahiro #endif /* ifndef __ASSEMBLY__ */
194819e50e2SAKASHI Takahiro
19536469703SDonglin Peng #ifndef __ASSEMBLY__
19636469703SDonglin Peng #ifdef CONFIG_FUNCTION_GRAPH_TRACER
19736469703SDonglin Peng struct fgraph_ret_regs {
19836469703SDonglin Peng /* x0 - x7 */
19936469703SDonglin Peng unsigned long regs[8];
20036469703SDonglin Peng
20136469703SDonglin Peng unsigned long fp;
20236469703SDonglin Peng unsigned long __unused;
20336469703SDonglin Peng };
20436469703SDonglin Peng
fgraph_ret_regs_return_value(struct fgraph_ret_regs * ret_regs)20536469703SDonglin Peng static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
20636469703SDonglin Peng {
20736469703SDonglin Peng return ret_regs->regs[0];
20836469703SDonglin Peng }
20936469703SDonglin Peng
fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs * ret_regs)21036469703SDonglin Peng static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
21136469703SDonglin Peng {
21236469703SDonglin Peng return ret_regs->fp;
21336469703SDonglin Peng }
214*7d8b31b7SArnd Bergmann
215*7d8b31b7SArnd Bergmann void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
216*7d8b31b7SArnd Bergmann unsigned long frame_pointer);
217*7d8b31b7SArnd Bergmann
21836469703SDonglin Peng #endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */
21936469703SDonglin Peng #endif
22036469703SDonglin Peng
221819e50e2SAKASHI Takahiro #endif /* __ASM_FTRACE_H */
222