blob: 6fa8535d3cceb55de7ecf1051fcb2c812dcb1f51 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Helge Dellerd75f0542009-02-09 00:43:36 +01002/*
3 * Code for tracing calls in Linux kernel.
Helge Deller366dd4e2016-04-13 22:27:22 +02004 * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
Helge Dellerd75f0542009-02-09 00:43:36 +01005 *
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
Helge Deller366dd4e2016-04-13 22:27:22 +020017#include <asm/assembly.h>
Helge Dellerd75f0542009-02-09 00:43:36 +010018#include <asm/sections.h>
19#include <asm/ftrace.h>
20
21
Helge Deller4df3c9e2016-04-29 22:07:31 +020022#define __hot __attribute__ ((__section__ (".text.hot")))
23
Helge Dellerd75f0542009-02-09 00:43:36 +010024#ifdef CONFIG_FUNCTION_GRAPH_TRACER
Helge Dellerd75f0542009-02-09 00:43:36 +010025/*
26 * Hook the return address and push it in the stack of return addrs
27 * in current thread info.
28 */
Helge Deller4df3c9e2016-04-29 22:07:31 +020029static void __hot prepare_ftrace_return(unsigned long *parent,
30 unsigned long self_addr)
Helge Dellerd75f0542009-02-09 00:43:36 +010031{
32 unsigned long old;
Helge Dellerd75f0542009-02-09 00:43:36 +010033 struct ftrace_graph_ent trace;
Helge Deller366dd4e2016-04-13 22:27:22 +020034 extern int parisc_return_to_handler;
Helge Dellerd75f0542009-02-09 00:43:36 +010035
Steven Rostedt (Red Hat)3a465882014-06-25 10:17:48 -040036 if (unlikely(ftrace_graph_is_dead()))
37 return;
38
Helge Dellerd75f0542009-02-09 00:43:36 +010039 if (unlikely(atomic_read(&current->tracing_graph_pause)))
40 return;
41
42 old = *parent;
Helge Dellerd75f0542009-02-09 00:43:36 +010043
44 trace.func = self_addr;
Helge Deller366dd4e2016-04-13 22:27:22 +020045 trace.depth = current->curr_ret_stack + 1;
Helge Dellerd75f0542009-02-09 00:43:36 +010046
47 /* Only trace if the calling function expects to */
Helge Deller366dd4e2016-04-13 22:27:22 +020048 if (!ftrace_graph_entry(&trace))
49 return;
Helge Dellerd75f0542009-02-09 00:43:36 +010050
Helge Deller366dd4e2016-04-13 22:27:22 +020051 if (ftrace_push_return_trace(old, self_addr, &trace.depth,
Josh Poimboeuf9a7c3482016-08-19 06:52:57 -050052 0, NULL) == -EBUSY)
Helge Deller366dd4e2016-04-13 22:27:22 +020053 return;
54
55 /* activate parisc_return_to_handler() as return point */
56 *parent = (unsigned long) &parisc_return_to_handler;
57}
Helge Dellerd75f0542009-02-09 00:43:36 +010058#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
59
Helge Deller4df3c9e2016-04-29 22:07:31 +020060void notrace __hot ftrace_function_trampoline(unsigned long parent,
Helge Dellerd75f0542009-02-09 00:43:36 +010061 unsigned long self_addr,
62 unsigned long org_sp_gr3)
63{
Helge Deller366dd4e2016-04-13 22:27:22 +020064 extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
65 extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
Helge Dellerd75f0542009-02-09 00:43:36 +010066
Helge Dellerd75f0542009-02-09 00:43:36 +010067 if (ftrace_trace_function != ftrace_stub) {
Helge Deller366dd4e2016-04-13 22:27:22 +020068 /* struct ftrace_ops *op, struct pt_regs *regs); */
69 ftrace_trace_function(parent, self_addr, NULL, NULL);
Helge Dellerd75f0542009-02-09 00:43:36 +010070 return;
71 }
Helge Deller366dd4e2016-04-13 22:27:22 +020072
Helge Dellerd75f0542009-02-09 00:43:36 +010073#ifdef CONFIG_FUNCTION_GRAPH_TRACER
Helge Deller366dd4e2016-04-13 22:27:22 +020074 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
75 ftrace_graph_entry != ftrace_graph_entry_stub) {
Helge Dellerd75f0542009-02-09 00:43:36 +010076 unsigned long *parent_rp;
77
Helge Dellerd75f0542009-02-09 00:43:36 +010078 /* calculate pointer to %rp in stack */
Helge Deller366dd4e2016-04-13 22:27:22 +020079 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
Helge Dellerd75f0542009-02-09 00:43:36 +010080 /* sanity check: parent_rp should hold parent */
81 if (*parent_rp != parent)
82 return;
Helge Deller366dd4e2016-04-13 22:27:22 +020083
Helge Dellerd75f0542009-02-09 00:43:36 +010084 prepare_ftrace_return(parent_rp, self_addr);
85 return;
86 }
87#endif
88}
89