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 struct ftrace_graph_ent trace; 34 extern int parisc_return_to_handler; 35 36 if (unlikely(ftrace_graph_is_dead())) 37 return; 38 39 if (unlikely(atomic_read(¤t->tracing_graph_pause))) 40 return; 41 42 old = *parent; 43 44 trace.func = self_addr; 45 trace.depth = current->curr_ret_stack + 1; 46 47 /* Only trace if the calling function expects to */ 48 if (!ftrace_graph_entry(&trace)) 49 return; 50 51 if (ftrace_push_return_trace(old, self_addr, &trace.depth, 52 0, NULL) == -EBUSY) 53 return; 54 55 /* activate parisc_return_to_handler() as return point */ 56 *parent = (unsigned long) &parisc_return_to_handler; 57 } 58 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 59 60 void notrace __hot ftrace_function_trampoline(unsigned long parent, 61 unsigned long self_addr, 62 unsigned long org_sp_gr3) 63 { 64 extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */ 65 extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace); 66 67 if (ftrace_trace_function != ftrace_stub) { 68 /* struct ftrace_ops *op, struct pt_regs *regs); */ 69 ftrace_trace_function(parent, self_addr, NULL, NULL); 70 return; 71 } 72 73 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 74 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || 75 ftrace_graph_entry != ftrace_graph_entry_stub) { 76 unsigned long *parent_rp; 77 78 /* calculate pointer to %rp in stack */ 79 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET); 80 /* sanity check: parent_rp should hold parent */ 81 if (*parent_rp != parent) 82 return; 83 84 prepare_ftrace_return(parent_rp, self_addr); 85 return; 86 } 87 #endif 88 } 89 90