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