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 #define __hot __attribute__ ((__section__ (".text.hot"))) 22 23 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 24 /* 25 * Hook the return address and push it in the stack of return addrs 26 * in current thread info. 27 */ 28 static void __hot prepare_ftrace_return(unsigned long *parent, 29 unsigned long self_addr) 30 { 31 unsigned long old; 32 struct ftrace_graph_ent trace; 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 trace.func = self_addr; 44 trace.depth = current->curr_ret_stack + 1; 45 46 /* Only trace if the calling function expects to */ 47 if (!ftrace_graph_entry(&trace)) 48 return; 49 50 if (ftrace_push_return_trace(old, self_addr, &trace.depth, 51 0 ) == -EBUSY) 52 return; 53 54 /* activate parisc_return_to_handler() as return point */ 55 *parent = (unsigned long) &parisc_return_to_handler; 56 } 57 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 58 59 void notrace __hot ftrace_function_trampoline(unsigned long parent, 60 unsigned long self_addr, 61 unsigned long org_sp_gr3) 62 { 63 extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */ 64 extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace); 65 66 if (ftrace_trace_function != ftrace_stub) { 67 /* struct ftrace_ops *op, struct pt_regs *regs); */ 68 ftrace_trace_function(parent, self_addr, NULL, NULL); 69 return; 70 } 71 72 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 73 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || 74 ftrace_graph_entry != ftrace_graph_entry_stub) { 75 unsigned long *parent_rp; 76 77 /* calculate pointer to %rp in stack */ 78 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET); 79 /* sanity check: parent_rp should hold parent */ 80 if (*parent_rp != parent) 81 return; 82 83 prepare_ftrace_return(parent_rp, self_addr); 84 return; 85 } 86 #endif 87 } 88 89