1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun #ifndef _ASM_S390_FTRACE_H 3*4882a593Smuzhiyun #define _ASM_S390_FTRACE_H 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun #define ARCH_SUPPORTS_FTRACE_OPS 1 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun #if defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT) 8*4882a593Smuzhiyun #define MCOUNT_INSN_SIZE 6 9*4882a593Smuzhiyun #else 10*4882a593Smuzhiyun #define MCOUNT_INSN_SIZE 24 11*4882a593Smuzhiyun #define MCOUNT_RETURN_FIXUP 18 12*4882a593Smuzhiyun #endif 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun #ifndef __ASSEMBLY__ 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun #ifdef CONFIG_CC_IS_CLANG 19*4882a593Smuzhiyun /* https://bugs.llvm.org/show_bug.cgi?id=41424 */ 20*4882a593Smuzhiyun #define ftrace_return_address(n) 0UL 21*4882a593Smuzhiyun #else 22*4882a593Smuzhiyun #define ftrace_return_address(n) __builtin_return_address(n) 23*4882a593Smuzhiyun #endif 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun void _mcount(void); 26*4882a593Smuzhiyun void ftrace_caller(void); 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun extern char ftrace_graph_caller_end; 29*4882a593Smuzhiyun extern unsigned long ftrace_plt; 30*4882a593Smuzhiyun extern void *ftrace_func; 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun struct dyn_arch_ftrace { }; 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun #define MCOUNT_ADDR ((unsigned long)_mcount) 35*4882a593Smuzhiyun #define FTRACE_ADDR ((unsigned long)ftrace_caller) 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun #define KPROBE_ON_FTRACE_NOP 0 38*4882a593Smuzhiyun #define KPROBE_ON_FTRACE_CALL 1 39*4882a593Smuzhiyun ftrace_call_adjust(unsigned long addr)40*4882a593Smuzhiyunstatic inline unsigned long ftrace_call_adjust(unsigned long addr) 41*4882a593Smuzhiyun { 42*4882a593Smuzhiyun return addr; 43*4882a593Smuzhiyun } 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun struct ftrace_insn { 46*4882a593Smuzhiyun u16 opc; 47*4882a593Smuzhiyun s32 disp; 48*4882a593Smuzhiyun } __packed; 49*4882a593Smuzhiyun ftrace_generate_nop_insn(struct ftrace_insn * insn)50*4882a593Smuzhiyunstatic inline void ftrace_generate_nop_insn(struct ftrace_insn *insn) 51*4882a593Smuzhiyun { 52*4882a593Smuzhiyun #ifdef CONFIG_FUNCTION_TRACER 53*4882a593Smuzhiyun #if defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT) 54*4882a593Smuzhiyun /* brcl 0,0 */ 55*4882a593Smuzhiyun insn->opc = 0xc004; 56*4882a593Smuzhiyun insn->disp = 0; 57*4882a593Smuzhiyun #else 58*4882a593Smuzhiyun /* jg .+24 */ 59*4882a593Smuzhiyun insn->opc = 0xc0f4; 60*4882a593Smuzhiyun insn->disp = MCOUNT_INSN_SIZE / 2; 61*4882a593Smuzhiyun #endif 62*4882a593Smuzhiyun #endif 63*4882a593Smuzhiyun } 64*4882a593Smuzhiyun is_ftrace_nop(struct ftrace_insn * insn)65*4882a593Smuzhiyunstatic inline int is_ftrace_nop(struct ftrace_insn *insn) 66*4882a593Smuzhiyun { 67*4882a593Smuzhiyun #ifdef CONFIG_FUNCTION_TRACER 68*4882a593Smuzhiyun #if defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT) 69*4882a593Smuzhiyun if (insn->disp == 0) 70*4882a593Smuzhiyun return 1; 71*4882a593Smuzhiyun #else 72*4882a593Smuzhiyun if (insn->disp == MCOUNT_INSN_SIZE / 2) 73*4882a593Smuzhiyun return 1; 74*4882a593Smuzhiyun #endif 75*4882a593Smuzhiyun #endif 76*4882a593Smuzhiyun return 0; 77*4882a593Smuzhiyun } 78*4882a593Smuzhiyun ftrace_generate_call_insn(struct ftrace_insn * insn,unsigned long ip)79*4882a593Smuzhiyunstatic inline void ftrace_generate_call_insn(struct ftrace_insn *insn, 80*4882a593Smuzhiyun unsigned long ip) 81*4882a593Smuzhiyun { 82*4882a593Smuzhiyun #ifdef CONFIG_FUNCTION_TRACER 83*4882a593Smuzhiyun unsigned long target; 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun /* brasl r0,ftrace_caller */ 86*4882a593Smuzhiyun target = is_module_addr((void *) ip) ? ftrace_plt : FTRACE_ADDR; 87*4882a593Smuzhiyun insn->opc = 0xc005; 88*4882a593Smuzhiyun insn->disp = (target - ip) / 2; 89*4882a593Smuzhiyun #endif 90*4882a593Smuzhiyun } 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun /* 93*4882a593Smuzhiyun * Even though the system call numbers are identical for s390/s390x a 94*4882a593Smuzhiyun * different system call table is used for compat tasks. This may lead 95*4882a593Smuzhiyun * to e.g. incorrect or missing trace event sysfs files. 96*4882a593Smuzhiyun * Therefore simply do not trace compat system calls at all. 97*4882a593Smuzhiyun * See kernel/trace/trace_syscalls.c. 98*4882a593Smuzhiyun */ 99*4882a593Smuzhiyun #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS arch_trace_is_compat_syscall(struct pt_regs * regs)100*4882a593Smuzhiyunstatic inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) 101*4882a593Smuzhiyun { 102*4882a593Smuzhiyun return is_compat_task(); 103*4882a593Smuzhiyun } 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME arch_syscall_match_sym_name(const char * sym,const char * name)106*4882a593Smuzhiyunstatic inline bool arch_syscall_match_sym_name(const char *sym, 107*4882a593Smuzhiyun const char *name) 108*4882a593Smuzhiyun { 109*4882a593Smuzhiyun /* 110*4882a593Smuzhiyun * Skip __s390_ and __s390x_ prefix - due to compat wrappers 111*4882a593Smuzhiyun * and aliasing some symbols of 64 bit system call functions 112*4882a593Smuzhiyun * may get the __s390_ prefix instead of the __s390x_ prefix. 113*4882a593Smuzhiyun */ 114*4882a593Smuzhiyun return !strcmp(sym + 7, name) || !strcmp(sym + 8, name); 115*4882a593Smuzhiyun } 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun #endif /* __ASSEMBLY__ */ 118*4882a593Smuzhiyun #endif /* _ASM_S390_FTRACE_H */ 119