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