1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_FTRACE_H 3 #define _ASM_X86_FTRACE_H 4 5 #include <asm/ptrace.h> 6 7 #ifdef CONFIG_FUNCTION_TRACER 8 #ifndef CC_USING_FENTRY 9 # error Compiler does not support fentry? 10 #endif 11 # define MCOUNT_ADDR ((unsigned long)(__fentry__)) 12 #define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */ 13 14 /* Ignore unused weak functions which will have non zero offsets */ 15 #ifdef CONFIG_HAVE_FENTRY 16 # include <asm/ibt.h> 17 /* Add offset for endbr64 if IBT enabled */ 18 # define FTRACE_MCOUNT_MAX_OFFSET ENDBR_INSN_SIZE 19 #endif 20 21 #ifdef CONFIG_DYNAMIC_FTRACE 22 #define ARCH_SUPPORTS_FTRACE_OPS 1 23 #endif 24 25 #ifndef __ASSEMBLY__ 26 extern void __fentry__(void); 27 28 static inline unsigned long ftrace_call_adjust(unsigned long addr) 29 { 30 /* 31 * addr is the address of the mcount call instruction. 32 * recordmcount does the necessary offset calculation. 33 */ 34 return addr; 35 } 36 37 #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS 38 39 #include <linux/ftrace_regs.h> 40 41 static __always_inline struct pt_regs * 42 arch_ftrace_get_regs(struct ftrace_regs *fregs) 43 { 44 /* Only when FL_SAVE_REGS is set, cs will be non zero */ 45 if (!arch_ftrace_regs(fregs)->regs.cs) 46 return NULL; 47 return &arch_ftrace_regs(fregs)->regs; 48 } 49 50 #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ 51 do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) 52 53 54 struct ftrace_ops; 55 #define ftrace_graph_func ftrace_graph_func 56 void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, 57 struct ftrace_ops *op, struct ftrace_regs *fregs); 58 #else 59 #define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR 60 #endif 61 62 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 63 /* 64 * When a ftrace registered caller is tracing a function that is 65 * also set by a register_ftrace_direct() call, it needs to be 66 * differentiated in the ftrace_caller trampoline. To do this, we 67 * place the direct caller in the ORIG_AX part of pt_regs. This 68 * tells the ftrace_caller that there's a direct caller. 69 */ 70 static inline void 71 __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) 72 { 73 /* Emulate a call */ 74 regs->orig_ax = addr; 75 } 76 #define arch_ftrace_set_direct_caller(fregs, addr) \ 77 __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) 78 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ 79 80 #ifdef CONFIG_DYNAMIC_FTRACE 81 82 struct dyn_arch_ftrace { 83 /* No extra data needed for x86 */ 84 }; 85 86 #endif /* CONFIG_DYNAMIC_FTRACE */ 87 #endif /* __ASSEMBLY__ */ 88 #endif /* CONFIG_FUNCTION_TRACER */ 89 90 91 #ifndef __ASSEMBLY__ 92 93 void prepare_ftrace_return(unsigned long ip, unsigned long *parent, 94 unsigned long frame_pointer); 95 96 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) 97 extern void set_ftrace_ops_ro(void); 98 #else 99 static inline void set_ftrace_ops_ro(void) { } 100 #endif 101 102 #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME 103 static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) 104 { 105 /* 106 * Compare the symbol name with the system call name. Skip the 107 * "__x64_sys", "__ia32_sys", "__do_sys" or simple "sys" prefix. 108 */ 109 return !strcmp(sym + 3, name + 3) || 110 (!strncmp(sym, "__x64_", 6) && !strcmp(sym + 9, name + 3)) || 111 (!strncmp(sym, "__ia32_", 7) && !strcmp(sym + 10, name + 3)) || 112 (!strncmp(sym, "__do_sys", 8) && !strcmp(sym + 8, name + 3)); 113 } 114 115 #ifndef COMPILE_OFFSETS 116 117 #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_IA32_EMULATION) 118 #include <linux/compat.h> 119 120 /* 121 * Because ia32 syscalls do not map to x86_64 syscall numbers 122 * this screws up the trace output when tracing a ia32 task. 123 * Instead of reporting bogus syscalls, just do not trace them. 124 * 125 * If the user really wants these, then they should use the 126 * raw syscall tracepoints with filtering. 127 */ 128 #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 1 129 static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) 130 { 131 return in_32bit_syscall(); 132 } 133 #endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_IA32_EMULATION */ 134 #endif /* !COMPILE_OFFSETS */ 135 #endif /* !__ASSEMBLY__ */ 136 137 #ifndef __ASSEMBLY__ 138 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 139 struct fgraph_ret_regs { 140 unsigned long ax; 141 unsigned long dx; 142 unsigned long bp; 143 }; 144 145 static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) 146 { 147 return ret_regs->ax; 148 } 149 150 static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) 151 { 152 return ret_regs->bp; 153 } 154 #endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ 155 #endif 156 157 #endif /* _ASM_X86_FTRACE_H */ 158