ftrace.c (c39f2d9db0fd81ea20bb5cce9b3f082ca63753e2) ftrace.c (657480d9c01574d1e11bbb29e725db9907daf782)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Dynamic function tracer architecture backend.
4 *
5 * Copyright IBM Corp. 2009,2014
6 *
7 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
8 * Martin Schwidefsky <schwidefsky@de.ibm.com>

--- 58 unchanged lines hidden (view full) ---

67 insn->disp = 0;
68#else
69 /* stg r14,8(r15) */
70 insn->opc = 0xe3e0;
71 insn->disp = 0xf0080024;
72#endif
73}
74
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Dynamic function tracer architecture backend.
4 *
5 * Copyright IBM Corp. 2009,2014
6 *
7 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
8 * Martin Schwidefsky <schwidefsky@de.ibm.com>

--- 58 unchanged lines hidden (view full) ---

67 insn->disp = 0;
68#else
69 /* stg r14,8(r15) */
70 insn->opc = 0xe3e0;
71 insn->disp = 0xf0080024;
72#endif
73}
74
75static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
76{
77#ifdef CONFIG_KPROBES
78 if (insn->opc == BREAKPOINT_INSTRUCTION)
79 return 1;
80#endif
81 return 0;
82}
83
84static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
85{
86#ifdef CONFIG_KPROBES
87 insn->opc = BREAKPOINT_INSTRUCTION;
88 insn->disp = KPROBE_ON_FTRACE_NOP;
89#endif
90}
91

--- 17 unchanged lines hidden (view full) ---

109 struct ftrace_insn orig, new, old;
110
111 if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
112 return -EFAULT;
113 if (addr == MCOUNT_ADDR) {
114 /* Initial code replacement */
115 ftrace_generate_orig_insn(&orig);
116 ftrace_generate_nop_insn(&new);
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

--- 17 unchanged lines hidden (view full) ---

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 /* Initial code replacement */
106 ftrace_generate_orig_insn(&orig);
107 ftrace_generate_nop_insn(&new);
117 } else if (is_kprobe_on_ftrace(&old)) {
118 /*
119 * If we find a breakpoint instruction, a kprobe has been
120 * placed at the beginning of the function. We write the
121 * constant KPROBE_ON_FTRACE_NOP into the remaining four
122 * bytes of the original instruction so that the kprobes
123 * handler can execute a nop, if it reaches this breakpoint.
124 */
125 ftrace_generate_kprobe_call_insn(&orig);
126 ftrace_generate_kprobe_nop_insn(&new);
127 } else {
128 /* Replace ftrace call with a nop. */
129 ftrace_generate_call_insn(&orig, rec->ip);
130 ftrace_generate_nop_insn(&new);
131 }
132 /* Verify that the to be replaced code matches what we expect. */
133 if (memcmp(&orig, &old, sizeof(old)))
134 return -EINVAL;
135 s390_kernel_write((void *) rec->ip, &new, sizeof(new));
136 return 0;
137}
138
139int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
140{
141 struct ftrace_insn orig, new, old;
142
143 if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
144 return -EFAULT;
108 } else {
109 /* Replace ftrace call with a nop. */
110 ftrace_generate_call_insn(&orig, rec->ip);
111 ftrace_generate_nop_insn(&new);
112 }
113 /* Verify that the to be replaced code matches what we expect. */
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;
145 if (is_kprobe_on_ftrace(&old)) {
146 /*
147 * If we find a breakpoint instruction, a kprobe has been
148 * placed at the beginning of the function. We write the
149 * constant KPROBE_ON_FTRACE_CALL into the remaining four
150 * bytes of the original instruction so that the kprobes
151 * handler can execute a brasl if it reaches this breakpoint.
152 */
153 ftrace_generate_kprobe_nop_insn(&orig);
154 ftrace_generate_kprobe_call_insn(&new);
155 } else {
156 /* Replace nop with an ftrace call. */
157 ftrace_generate_nop_insn(&orig);
158 ftrace_generate_call_insn(&new, rec->ip);
159 }
126 /* Replace nop with an ftrace call. */
127 ftrace_generate_nop_insn(&orig);
128 ftrace_generate_call_insn(&new, rec->ip);
129
160 /* Verify that the to be replaced code matches what we expect. */
161 if (memcmp(&orig, &old, sizeof(old)))
162 return -EINVAL;
163 s390_kernel_write((void *) rec->ip, &new, sizeof(new));
164 return 0;
165}
166
167int ftrace_update_ftrace_func(ftrace_func_t func)

--- 68 unchanged lines hidden (view full) ---

236{
237 u8 op = 0xf4; /* set mask field to all ones */
238
239 s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
240 return 0;
241}
242
243#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
130 /* Verify that the to be replaced code matches what we expect. */
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)

--- 68 unchanged lines hidden (view full) ---

206{
207 u8 op = 0xf4; /* set mask field to all ones */
208
209 s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
210 return 0;
211}
212
213#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
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