1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Code for tracing calls in Linux kernel. 4 * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de> 5 * 6 * based on code for x86 which is: 7 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> 8 * 9 * future possible enhancements: 10 * - add CONFIG_DYNAMIC_FTRACE 11 * - add CONFIG_STACK_TRACER 12 */ 13 14 #include <linux/init.h> 15 #include <linux/ftrace.h> 16 17 #include <asm/assembly.h> 18 #include <asm/sections.h> 19 #include <asm/ftrace.h> 20 21 22 #define __hot __attribute__ ((__section__ (".text.hot"))) 23 24 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 25 /* 26 * Hook the return address and push it in the stack of return addrs 27 * in current thread info. 28 */ 29 static void __hot prepare_ftrace_return(unsigned long *parent, 30 unsigned long self_addr) 31 { 32 unsigned long old; 33 extern int parisc_return_to_handler; 34 35 if (unlikely(ftrace_graph_is_dead())) 36 return; 37 38 if (unlikely(atomic_read(¤t->tracing_graph_pause))) 39 return; 40 41 old = *parent; 42 43 if (!function_graph_enter(old, self_addr, 0, NULL)) 44 /* activate parisc_return_to_handler() as return point */ 45 *parent = (unsigned long) &parisc_return_to_handler; 46 } 47 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 48 49 void notrace __hot ftrace_function_trampoline(unsigned long parent, 50 unsigned long self_addr, 51 unsigned long org_sp_gr3) 52 { 53 extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */ 54 extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace); 55 56 if (ftrace_trace_function != ftrace_stub) { 57 /* struct ftrace_ops *op, struct pt_regs *regs); */ 58 ftrace_trace_function(parent, self_addr, NULL, NULL); 59 return; 60 } 61 62 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 63 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || 64 ftrace_graph_entry != ftrace_graph_entry_stub) { 65 unsigned long *parent_rp; 66 67 /* calculate pointer to %rp in stack */ 68 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET); 69 /* sanity check: parent_rp should hold parent */ 70 if (*parent_rp != parent) 71 return; 72 73 prepare_ftrace_return(parent_rp, self_addr); 74 return; 75 } 76 #endif 77 } 78 79