1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/init.h>
14#include <linux/ftrace.h>
15#include <linux/uaccess.h>
16
17#include <asm/assembly.h>
18#include <asm/sections.h>
19#include <asm/ftrace.h>
20#include <asm/patch.h>
21
22#define __hot __attribute__ ((__section__ (".text.hot")))
23
24#ifdef CONFIG_FUNCTION_GRAPH_TRACER
25
26
27
28
29static void __hot prepare_ftrace_return(unsigned long *parent,
30 unsigned long self_addr)
31{
32 unsigned long old;
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 if (!function_graph_enter(old, self_addr, 0, NULL))
44
45 *parent = (unsigned long) &parisc_return_to_handler;
46}
47#endif
48
49void notrace __hot ftrace_function_trampoline(unsigned long parent,
50 unsigned long self_addr,
51 unsigned long org_sp_gr3)
52{
53#ifndef CONFIG_DYNAMIC_FTRACE
54 extern ftrace_func_t ftrace_trace_function;
55#endif
56 if (ftrace_trace_function != ftrace_stub)
57 ftrace_trace_function(self_addr, parent, NULL, NULL);
58
59#ifdef CONFIG_FUNCTION_GRAPH_TRACER
60 if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
61 ftrace_graph_entry != ftrace_graph_entry_stub) {
62 unsigned long *parent_rp;
63
64
65 parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
66
67 if (*parent_rp != parent)
68 return;
69
70 prepare_ftrace_return(parent_rp, self_addr);
71 return;
72 }
73#endif
74}
75
76#ifdef CONFIG_FUNCTION_GRAPH_TRACER
77int ftrace_enable_ftrace_graph_caller(void)
78{
79 return 0;
80}
81
82int ftrace_disable_ftrace_graph_caller(void)
83{
84 return 0;
85}
86#endif
87
88#ifdef CONFIG_DYNAMIC_FTRACE
89
90int __init ftrace_dyn_arch_init(void)
91{
92 return 0;
93}
94int ftrace_update_ftrace_func(ftrace_func_t func)
95{
96 return 0;
97}
98
99unsigned long ftrace_call_adjust(unsigned long addr)
100{
101 return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
102}
103
104int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
105{
106 u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
107 u32 *tramp;
108 int size, ret, i;
109 void *ip;
110
111#ifdef CONFIG_64BIT
112 unsigned long addr2 =
113 (unsigned long)dereference_function_descriptor((void *)addr);
114
115 u32 ftrace_trampoline[] = {
116 0x73c10208,
117 0x0c2110c1,
118 0xe820d002,
119 addr2 >> 32,
120 addr2 & 0xffffffff,
121 0xe83f1fd7,
122 };
123
124 u32 ftrace_trampoline_unaligned[] = {
125 addr2 >> 32,
126 addr2 & 0xffffffff,
127 0x37de0200,
128 0x73c13e01,
129 0x34213ff9,
130 0x50213fc1,
131 0xe820d002,
132 0xe83f1fcf,
133 };
134
135 BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline_unaligned) >
136 FTRACE_PATCHABLE_FUNCTION_SIZE);
137#else
138 u32 ftrace_trampoline[] = {
139 (u32)addr,
140 0x6fc10080,
141 0x48213fd1,
142 0xe820c002,
143 0xe83f1fdf,
144 };
145#endif
146
147 BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline) >
148 FTRACE_PATCHABLE_FUNCTION_SIZE);
149
150 size = sizeof(ftrace_trampoline);
151 tramp = ftrace_trampoline;
152
153#ifdef CONFIG_64BIT
154 if (rec->ip & 0x4) {
155 size = sizeof(ftrace_trampoline_unaligned);
156 tramp = ftrace_trampoline_unaligned;
157 }
158#endif
159
160 ip = (void *)(rec->ip + 4 - size);
161
162 ret = probe_kernel_read(insn, ip, size);
163 if (ret)
164 return ret;
165
166 for (i = 0; i < size / 4; i++) {
167 if (insn[i] != INSN_NOP)
168 return -EINVAL;
169 }
170
171 __patch_text_multiple(ip, tramp, size);
172 return 0;
173}
174
175int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
176 unsigned long addr)
177{
178 u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
179 int i;
180
181 for (i = 0; i < ARRAY_SIZE(insn); i++)
182 insn[i] = INSN_NOP;
183
184 __patch_text((void *)rec->ip, INSN_NOP);
185 __patch_text_multiple((void *)rec->ip + 4 - sizeof(insn),
186 insn, sizeof(insn)-4);
187 return 0;
188}
189#endif
190