1
2
3
4
5
6
7
8
9
10#include <linux/moduleloader.h>
11#include <linux/hardirq.h>
12#include <linux/uaccess.h>
13#include <linux/ftrace.h>
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/kprobes.h>
17#include <trace/syscall.h>
18#include <asm/asm-offsets.h>
19#include <asm/cacheflush.h>
20#include <asm/set_memory.h>
21#include "entry.h"
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59unsigned long ftrace_plt;
60
61static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
62{
63#ifdef CC_USING_HOTPATCH
64
65 insn->opc = 0xc004;
66 insn->disp = 0;
67#else
68
69 insn->opc = 0xe3e0;
70 insn->disp = 0xf0080024;
71#endif
72}
73
74static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
75{
76#ifdef CONFIG_KPROBES
77 if (insn->opc == BREAKPOINT_INSTRUCTION)
78 return 1;
79#endif
80 return 0;
81}
82
83static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
84{
85#ifdef CONFIG_KPROBES
86 insn->opc = BREAKPOINT_INSTRUCTION;
87 insn->disp = KPROBE_ON_FTRACE_NOP;
88#endif
89}
90
91static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn)
92{
93#ifdef CONFIG_KPROBES
94 insn->opc = BREAKPOINT_INSTRUCTION;
95 insn->disp = KPROBE_ON_FTRACE_CALL;
96#endif
97}
98
99int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
100 unsigned long addr)
101{
102 return 0;
103}
104
105int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
106 unsigned long addr)
107{
108 struct ftrace_insn orig, new, old;
109
110 if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
111 return -EFAULT;
112 if (addr == MCOUNT_ADDR) {
113
114 ftrace_generate_orig_insn(&orig);
115 ftrace_generate_nop_insn(&new);
116 } else if (is_kprobe_on_ftrace(&old)) {
117
118
119
120
121
122
123
124 ftrace_generate_kprobe_call_insn(&orig);
125 ftrace_generate_kprobe_nop_insn(&new);
126 } else {
127
128 ftrace_generate_call_insn(&orig, rec->ip);
129 ftrace_generate_nop_insn(&new);
130 }
131
132 if (memcmp(&orig, &old, sizeof(old)))
133 return -EINVAL;
134 s390_kernel_write((void *) rec->ip, &new, sizeof(new));
135 return 0;
136}
137
138int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
139{
140 struct ftrace_insn orig, new, old;
141
142 if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
143 return -EFAULT;
144 if (is_kprobe_on_ftrace(&old)) {
145
146
147
148
149
150
151
152 ftrace_generate_kprobe_nop_insn(&orig);
153 ftrace_generate_kprobe_call_insn(&new);
154 } else {
155
156 ftrace_generate_nop_insn(&orig);
157 ftrace_generate_call_insn(&new, rec->ip);
158 }
159
160 if (memcmp(&orig, &old, sizeof(old)))
161 return -EINVAL;
162 s390_kernel_write((void *) rec->ip, &new, sizeof(new));
163 return 0;
164}
165
166int ftrace_update_ftrace_func(ftrace_func_t func)
167{
168 return 0;
169}
170
171int __init ftrace_dyn_arch_init(void)
172{
173 return 0;
174}
175
176#ifdef CONFIG_MODULES
177
178static int __init ftrace_plt_init(void)
179{
180 unsigned int *ip;
181
182 ftrace_plt = (unsigned long) module_alloc(PAGE_SIZE);
183 if (!ftrace_plt)
184 panic("cannot allocate ftrace plt\n");
185 ip = (unsigned int *) ftrace_plt;
186 ip[0] = 0x0d10e310;
187 ip[1] = 0x100a0004;
188 ip[2] = 0x07f10000;
189 ip[3] = FTRACE_ADDR >> 32;
190 ip[4] = FTRACE_ADDR & 0xffffffff;
191 set_memory_ro(ftrace_plt, 1);
192 return 0;
193}
194device_initcall(ftrace_plt_init);
195
196#endif
197
198#ifdef CONFIG_FUNCTION_GRAPH_TRACER
199
200
201
202
203unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
204{
205 struct ftrace_graph_ent trace;
206
207 if (unlikely(ftrace_graph_is_dead()))
208 goto out;
209 if (unlikely(atomic_read(¤t->tracing_graph_pause)))
210 goto out;
211 ip -= MCOUNT_INSN_SIZE;
212 trace.func = ip;
213 trace.depth = current->curr_ret_stack + 1;
214
215 if (!ftrace_graph_entry(&trace))
216 goto out;
217 if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
218 NULL) == -EBUSY)
219 goto out;
220 parent = (unsigned long) return_to_handler;
221out:
222 return parent;
223}
224NOKPROBE_SYMBOL(prepare_ftrace_return);
225
226
227
228
229
230
231
232
233
234int ftrace_enable_ftrace_graph_caller(void)
235{
236 u8 op = 0x04;
237
238 s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
239 return 0;
240}
241
242int ftrace_disable_ftrace_graph_caller(void)
243{
244 u8 op = 0xf4;
245
246 s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
247 return 0;
248}
249
250#endif
251