]> Git Repo - linux.git/blame - arch/parisc/kernel/ftrace.c
parisc/ftrace: Add ARCH_SUPPORTS_FTRACE_OPS support
[linux.git] / arch / parisc / kernel / ftrace.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
d75f054a
HD
2/*
3 * Code for tracing calls in Linux kernel.
366dd4ea 4 * Copyright (C) 2009-2016 Helge Deller <[email protected]>
d75f054a
HD
5 *
6 * based on code for x86 which is:
7 * Copyright (C) 2007-2008 Steven Rostedt <[email protected]>
8 *
9 * future possible enhancements:
d75f054a
HD
10 * - add CONFIG_STACK_TRACER
11 */
12
13#include <linux/init.h>
14#include <linux/ftrace.h>
6ca63662 15#include <linux/uaccess.h>
d75f054a 16
366dd4ea 17#include <asm/assembly.h>
d75f054a
HD
18#include <asm/sections.h>
19#include <asm/ftrace.h>
6ca63662 20#include <asm/patch.h>
d75f054a 21
4df3c9ec
HD
22#define __hot __attribute__ ((__section__ (".text.hot")))
23
d75f054a 24#ifdef CONFIG_FUNCTION_GRAPH_TRACER
d75f054a
HD
25/*
26 * Hook the return address and push it in the stack of return addrs
27 * in current thread info.
28 */
4df3c9ec
HD
29static void __hot prepare_ftrace_return(unsigned long *parent,
30 unsigned long self_addr)
d75f054a
HD
31{
32 unsigned long old;
366dd4ea 33 extern int parisc_return_to_handler;
d75f054a 34
3a46588e
SRRH
35 if (unlikely(ftrace_graph_is_dead()))
36 return;
37
d75f054a
HD
38 if (unlikely(atomic_read(&current->tracing_graph_pause)))
39 return;
40
41 old = *parent;
d75f054a 42
a87532c7
SRV
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;
d75f054a 46}
d75f054a
HD
47#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
48
4df3c9ec 49void notrace __hot ftrace_function_trampoline(unsigned long parent,
d75f054a
HD
50 unsigned long self_addr,
51 unsigned long org_sp_gr3)
52{
6ca63662
SS
53#ifndef CONFIG_DYNAMIC_FTRACE
54 extern ftrace_func_t ftrace_trace_function;
55#endif
d562aca3
SS
56 extern struct ftrace_ops *function_trace_op;
57
58 if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED &&
59 ftrace_trace_function != ftrace_stub)
60 ftrace_trace_function(self_addr, parent,
61 function_trace_op, NULL);
366dd4ea 62
d75f054a 63#ifdef CONFIG_FUNCTION_GRAPH_TRACER
366dd4ea
HD
64 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
65 ftrace_graph_entry != ftrace_graph_entry_stub) {
d75f054a
HD
66 unsigned long *parent_rp;
67
d75f054a 68 /* calculate pointer to %rp in stack */
366dd4ea 69 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
d75f054a
HD
70 /* sanity check: parent_rp should hold parent */
71 if (*parent_rp != parent)
72 return;
366dd4ea 73
d75f054a
HD
74 prepare_ftrace_return(parent_rp, self_addr);
75 return;
76 }
77#endif
78}
79
6ca63662
SS
80#ifdef CONFIG_FUNCTION_GRAPH_TRACER
81int ftrace_enable_ftrace_graph_caller(void)
82{
83 return 0;
84}
85
86int ftrace_disable_ftrace_graph_caller(void)
87{
88 return 0;
89}
90#endif
91
92#ifdef CONFIG_DYNAMIC_FTRACE
93
94int __init ftrace_dyn_arch_init(void)
95{
96 return 0;
97}
98int ftrace_update_ftrace_func(ftrace_func_t func)
99{
100 return 0;
101}
102
103unsigned long ftrace_call_adjust(unsigned long addr)
104{
105 return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
106}
107
108int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
109{
110 u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
111 u32 *tramp;
112 int size, ret, i;
113 void *ip;
114
115#ifdef CONFIG_64BIT
116 unsigned long addr2 =
117 (unsigned long)dereference_function_descriptor((void *)addr);
118
119 u32 ftrace_trampoline[] = {
120 0x73c10208, /* std,ma r1,100(sp) */
121 0x0c2110c1, /* ldd -10(r1),r1 */
122 0xe820d002, /* bve,n (r1) */
123 addr2 >> 32,
124 addr2 & 0xffffffff,
125 0xe83f1fd7, /* b,l,n .-14,r1 */
126 };
127
128 u32 ftrace_trampoline_unaligned[] = {
129 addr2 >> 32,
130 addr2 & 0xffffffff,
131 0x37de0200, /* ldo 100(sp),sp */
132 0x73c13e01, /* std r1,-100(sp) */
133 0x34213ff9, /* ldo -4(r1),r1 */
134 0x50213fc1, /* ldd -20(r1),r1 */
135 0xe820d002, /* bve,n (r1) */
136 0xe83f1fcf, /* b,l,n .-20,r1 */
137 };
138
139 BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline_unaligned) >
140 FTRACE_PATCHABLE_FUNCTION_SIZE);
141#else
142 u32 ftrace_trampoline[] = {
143 (u32)addr,
144 0x6fc10080, /* stw,ma r1,40(sp) */
145 0x48213fd1, /* ldw -18(r1),r1 */
146 0xe820c002, /* bv,n r0(r1) */
147 0xe83f1fdf, /* b,l,n .-c,r1 */
148 };
149#endif
150
151 BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline) >
152 FTRACE_PATCHABLE_FUNCTION_SIZE);
153
154 size = sizeof(ftrace_trampoline);
155 tramp = ftrace_trampoline;
156
157#ifdef CONFIG_64BIT
158 if (rec->ip & 0x4) {
159 size = sizeof(ftrace_trampoline_unaligned);
160 tramp = ftrace_trampoline_unaligned;
161 }
162#endif
163
164 ip = (void *)(rec->ip + 4 - size);
165
166 ret = probe_kernel_read(insn, ip, size);
167 if (ret)
168 return ret;
169
170 for (i = 0; i < size / 4; i++) {
171 if (insn[i] != INSN_NOP)
172 return -EINVAL;
173 }
174
175 __patch_text_multiple(ip, tramp, size);
176 return 0;
177}
178
179int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
180 unsigned long addr)
181{
182 u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
183 int i;
184
185 for (i = 0; i < ARRAY_SIZE(insn); i++)
186 insn[i] = INSN_NOP;
187
740f05f3 188 __patch_text((void *)rec->ip, INSN_NOP);
6ca63662 189 __patch_text_multiple((void *)rec->ip + 4 - sizeof(insn),
740f05f3 190 insn, sizeof(insn)-4);
6ca63662
SS
191 return 0;
192}
193#endif
This page took 0.558132 seconds and 4 git commands to generate.