| 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 __ASSEMBLER__ | 
|---|
| 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 | static inline unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip) | 
|---|
| 38 | { | 
|---|
| 39 | if (is_endbr((void*)(fentry_ip - ENDBR_INSN_SIZE))) | 
|---|
| 40 | fentry_ip -= ENDBR_INSN_SIZE; | 
|---|
| 41 |  | 
|---|
| 42 | return fentry_ip; | 
|---|
| 43 | } | 
|---|
| 44 | #define ftrace_get_symaddr(fentry_ip)	arch_ftrace_get_symaddr(fentry_ip) | 
|---|
| 45 |  | 
|---|
| 46 | #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS | 
|---|
| 47 |  | 
|---|
| 48 | #include <linux/ftrace_regs.h> | 
|---|
| 49 |  | 
|---|
| 50 | static __always_inline struct pt_regs * | 
|---|
| 51 | arch_ftrace_get_regs(struct ftrace_regs *fregs) | 
|---|
| 52 | { | 
|---|
| 53 | /* Only when FL_SAVE_REGS is set, cs will be non zero */ | 
|---|
| 54 | if (!arch_ftrace_regs(fregs)->regs.cs) | 
|---|
| 55 | return NULL; | 
|---|
| 56 | return &arch_ftrace_regs(fregs)->regs; | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | #define arch_ftrace_fill_perf_regs(fregs, _regs) do {	\ | 
|---|
| 60 | (_regs)->ip = arch_ftrace_regs(fregs)->regs.ip;		\ | 
|---|
| 61 | (_regs)->sp = arch_ftrace_regs(fregs)->regs.sp;		\ | 
|---|
| 62 | (_regs)->cs = __KERNEL_CS;		\ | 
|---|
| 63 | (_regs)->flags = 0;			\ | 
|---|
| 64 | } while (0) | 
|---|
| 65 |  | 
|---|
| 66 | #define ftrace_regs_set_instruction_pointer(fregs, _ip)	\ | 
|---|
| 67 | do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) | 
|---|
| 68 |  | 
|---|
| 69 |  | 
|---|
| 70 | static __always_inline unsigned long | 
|---|
| 71 | ftrace_regs_get_return_address(struct ftrace_regs *fregs) | 
|---|
| 72 | { | 
|---|
| 73 | return *(unsigned long *)ftrace_regs_get_stack_pointer(fregs); | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | struct ftrace_ops; | 
|---|
| 77 | #define ftrace_graph_func ftrace_graph_func | 
|---|
| 78 | void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, | 
|---|
| 79 | struct ftrace_ops *op, struct ftrace_regs *fregs); | 
|---|
| 80 | #else | 
|---|
| 81 | #define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR | 
|---|
| 82 | #endif | 
|---|
| 83 |  | 
|---|
| 84 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS | 
|---|
| 85 | /* | 
|---|
| 86 | * When a ftrace registered caller is tracing a function that is | 
|---|
| 87 | * also set by a register_ftrace_direct() call, it needs to be | 
|---|
| 88 | * differentiated in the ftrace_caller trampoline. To do this, we | 
|---|
| 89 | * place the direct caller in the ORIG_AX part of pt_regs. This | 
|---|
| 90 | * tells the ftrace_caller that there's a direct caller. | 
|---|
| 91 | */ | 
|---|
| 92 | static inline void | 
|---|
| 93 | __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) | 
|---|
| 94 | { | 
|---|
| 95 | /* Emulate a call */ | 
|---|
| 96 | regs->orig_ax = addr; | 
|---|
| 97 | } | 
|---|
| 98 | #define arch_ftrace_set_direct_caller(fregs, addr) \ | 
|---|
| 99 | __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) | 
|---|
| 100 | #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ | 
|---|
| 101 |  | 
|---|
| 102 | #ifdef CONFIG_DYNAMIC_FTRACE | 
|---|
| 103 |  | 
|---|
| 104 | struct dyn_arch_ftrace { | 
|---|
| 105 | /* No extra data needed for x86 */ | 
|---|
| 106 | }; | 
|---|
| 107 |  | 
|---|
| 108 | #endif /*  CONFIG_DYNAMIC_FTRACE */ | 
|---|
| 109 | #endif /* __ASSEMBLER__ */ | 
|---|
| 110 | #endif /* CONFIG_FUNCTION_TRACER */ | 
|---|
| 111 |  | 
|---|
| 112 |  | 
|---|
| 113 | #ifndef __ASSEMBLER__ | 
|---|
| 114 |  | 
|---|
| 115 | void prepare_ftrace_return(unsigned long ip, unsigned long *parent, | 
|---|
| 116 | unsigned long frame_pointer); | 
|---|
| 117 |  | 
|---|
| 118 | #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) | 
|---|
| 119 | extern void set_ftrace_ops_ro(void); | 
|---|
| 120 | #else | 
|---|
| 121 | static inline void set_ftrace_ops_ro(void) { } | 
|---|
| 122 | #endif | 
|---|
| 123 |  | 
|---|
| 124 | #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME | 
|---|
| 125 | static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) | 
|---|
| 126 | { | 
|---|
| 127 | /* | 
|---|
| 128 | * Compare the symbol name with the system call name. Skip the | 
|---|
| 129 | * "__x64_sys", "__ia32_sys", "__do_sys" or simple "sys" prefix. | 
|---|
| 130 | */ | 
|---|
| 131 | return !strcmp(sym + 3, name + 3) || | 
|---|
| 132 | (!strncmp(sym, "__x64_", 6) && !strcmp(sym + 9, name + 3)) || | 
|---|
| 133 | (!strncmp(sym, "__ia32_", 7) && !strcmp(sym + 10, name + 3)) || | 
|---|
| 134 | (!strncmp(sym, "__do_sys", 8) && !strcmp(sym + 8, name + 3)); | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | #ifndef COMPILE_OFFSETS | 
|---|
| 138 |  | 
|---|
| 139 | #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_IA32_EMULATION) | 
|---|
| 140 | #include <linux/compat.h> | 
|---|
| 141 |  | 
|---|
| 142 | /* | 
|---|
| 143 | * Because ia32 syscalls do not map to x86_64 syscall numbers | 
|---|
| 144 | * this screws up the trace output when tracing a ia32 task. | 
|---|
| 145 | * Instead of reporting bogus syscalls, just do not trace them. | 
|---|
| 146 | * | 
|---|
| 147 | * If the user really wants these, then they should use the | 
|---|
| 148 | * raw syscall tracepoints with filtering. | 
|---|
| 149 | */ | 
|---|
| 150 | #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 1 | 
|---|
| 151 | static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) | 
|---|
| 152 | { | 
|---|
| 153 | return in_32bit_syscall(); | 
|---|
| 154 | } | 
|---|
| 155 | #endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_IA32_EMULATION */ | 
|---|
| 156 | #endif /* !COMPILE_OFFSETS */ | 
|---|
| 157 | #endif /* !__ASSEMBLER__ */ | 
|---|
| 158 |  | 
|---|
| 159 | #endif /* _ASM_X86_FTRACE_H */ | 
|---|
| 160 |  | 
|---|