1
2
3
4
5
6
7
8
9
10
11
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/spinlock.h>
15#include <linux/hardirq.h>
16#include <linux/uaccess.h>
17#include <linux/ftrace.h>
18#include <linux/percpu.h>
19#include <linux/sched.h>
20#include <linux/init.h>
21#include <linux/list.h>
22#include <linux/module.h>
23
24#include <trace/syscall.h>
25
26#include <asm/cacheflush.h>
27#include <asm/kprobes.h>
28#include <asm/ftrace.h>
29#include <asm/nops.h>
30
31#ifdef CONFIG_DYNAMIC_FTRACE
32
33int ftrace_arch_code_modify_prepare(void)
34{
35 set_kernel_text_rw();
36 set_all_modules_text_rw();
37 return 0;
38}
39
40int ftrace_arch_code_modify_post_process(void)
41{
42 set_all_modules_text_ro();
43 set_kernel_text_ro();
44 return 0;
45}
46
47union ftrace_code_union {
48 char code[MCOUNT_INSN_SIZE];
49 struct {
50 char e8;
51 int offset;
52 } __attribute__((packed));
53};
54
55static int ftrace_calc_offset(long ip, long addr)
56{
57 return (int)(addr - ip);
58}
59
60static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
61{
62 static union ftrace_code_union calc;
63
64 calc.e8 = 0xe8;
65 calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
66
67
68
69
70
71 return calc.code;
72}
73
74static inline int
75within(unsigned long addr, unsigned long start, unsigned long end)
76{
77 return addr >= start && addr < end;
78}
79
80static unsigned long text_ip_addr(unsigned long ip)
81{
82
83
84
85
86
87
88
89
90 if (within(ip, (unsigned long)_text, (unsigned long)_etext))
91 ip = (unsigned long)__va(__pa_symbol(ip));
92
93 return ip;
94}
95
96static const unsigned char *ftrace_nop_replace(void)
97{
98 return ideal_nops[NOP_ATOMIC5];
99}
100
101static int
102ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
103 unsigned const char *new_code)
104{
105 unsigned char replaced[MCOUNT_INSN_SIZE];
106
107
108
109
110
111
112
113
114
115
116
117
118 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
119 return -EFAULT;
120
121
122 if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
123 return -EINVAL;
124
125 ip = text_ip_addr(ip);
126
127
128 if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
129 return -EPERM;
130
131 sync_core();
132
133 return 0;
134}
135
136int ftrace_make_nop(struct module *mod,
137 struct dyn_ftrace *rec, unsigned long addr)
138{
139 unsigned const char *new, *old;
140 unsigned long ip = rec->ip;
141
142 old = ftrace_call_replace(ip, addr);
143 new = ftrace_nop_replace();
144
145
146
147
148
149
150
151
152
153 if (addr == MCOUNT_ADDR)
154 return ftrace_modify_code_direct(rec->ip, old, new);
155
156
157 WARN_ONCE(1, "invalid use of ftrace_make_nop");
158 return -EINVAL;
159}
160
161int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
162{
163 unsigned const char *new, *old;
164 unsigned long ip = rec->ip;
165
166 old = ftrace_nop_replace();
167 new = ftrace_call_replace(ip, addr);
168
169
170 return ftrace_modify_code_direct(rec->ip, old, new);
171}
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204atomic_t modifying_ftrace_code __read_mostly;
205
206static int
207ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
208 unsigned const char *new_code);
209
210
211
212
213
214
215
216
217
218int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
219 unsigned long addr)
220{
221 WARN_ON(1);
222 return -EINVAL;
223}
224
225static unsigned long ftrace_update_func;
226
227static int update_ftrace_func(unsigned long ip, void *new)
228{
229 unsigned char old[MCOUNT_INSN_SIZE];
230 int ret;
231
232 memcpy(old, (void *)ip, MCOUNT_INSN_SIZE);
233
234 ftrace_update_func = ip;
235
236 smp_wmb();
237
238
239 atomic_inc(&modifying_ftrace_code);
240
241 ret = ftrace_modify_code(ip, old, new);
242
243 atomic_dec(&modifying_ftrace_code);
244
245 return ret;
246}
247
248int ftrace_update_ftrace_func(ftrace_func_t func)
249{
250 unsigned long ip = (unsigned long)(&ftrace_call);
251 unsigned char *new;
252 int ret;
253
254 new = ftrace_call_replace(ip, (unsigned long)func);
255 ret = update_ftrace_func(ip, new);
256
257
258 if (!ret) {
259 ip = (unsigned long)(&ftrace_regs_call);
260 new = ftrace_call_replace(ip, (unsigned long)func);
261 ret = update_ftrace_func(ip, new);
262 }
263
264 return ret;
265}
266
267static int is_ftrace_caller(unsigned long ip)
268{
269 if (ip == ftrace_update_func)
270 return 1;
271
272 return 0;
273}
274
275
276
277
278
279
280
281
282int ftrace_int3_handler(struct pt_regs *regs)
283{
284 unsigned long ip;
285
286 if (WARN_ON_ONCE(!regs))
287 return 0;
288
289 ip = regs->ip - 1;
290 if (!ftrace_location(ip) && !is_ftrace_caller(ip))
291 return 0;
292
293 regs->ip += MCOUNT_INSN_SIZE - 1;
294
295 return 1;
296}
297
298static int ftrace_write(unsigned long ip, const char *val, int size)
299{
300
301
302
303
304
305
306
307
308 if (within(ip, (unsigned long)_text, (unsigned long)_etext))
309 ip = (unsigned long)__va(__pa_symbol(ip));
310
311 if (probe_kernel_write((void *)ip, val, size))
312 return -EPERM;
313
314 return 0;
315}
316
317static int add_break(unsigned long ip, const char *old)
318{
319 unsigned char replaced[MCOUNT_INSN_SIZE];
320 unsigned char brk = BREAKPOINT_INSTRUCTION;
321
322 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
323 return -EFAULT;
324
325
326 if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
327 return -EINVAL;
328
329 return ftrace_write(ip, &brk, 1);
330}
331
332static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
333{
334 unsigned const char *old;
335 unsigned long ip = rec->ip;
336
337 old = ftrace_call_replace(ip, addr);
338
339 return add_break(rec->ip, old);
340}
341
342
343static int add_brk_on_nop(struct dyn_ftrace *rec)
344{
345 unsigned const char *old;
346
347 old = ftrace_nop_replace();
348
349 return add_break(rec->ip, old);
350}
351
352
353
354
355
356
357static unsigned long get_ftrace_addr(struct dyn_ftrace *rec)
358{
359 if (rec->flags & FTRACE_FL_REGS)
360 return (unsigned long)FTRACE_REGS_ADDR;
361 else
362 return (unsigned long)FTRACE_ADDR;
363}
364
365
366
367
368
369
370static unsigned long get_ftrace_old_addr(struct dyn_ftrace *rec)
371{
372 if (rec->flags & FTRACE_FL_REGS_EN)
373 return (unsigned long)FTRACE_REGS_ADDR;
374 else
375 return (unsigned long)FTRACE_ADDR;
376}
377
378static int add_breakpoints(struct dyn_ftrace *rec, int enable)
379{
380 unsigned long ftrace_addr;
381 int ret;
382
383 ret = ftrace_test_record(rec, enable);
384
385 ftrace_addr = get_ftrace_addr(rec);
386
387 switch (ret) {
388 case FTRACE_UPDATE_IGNORE:
389 return 0;
390
391 case FTRACE_UPDATE_MAKE_CALL:
392
393 return add_brk_on_nop(rec);
394
395 case FTRACE_UPDATE_MODIFY_CALL_REGS:
396 case FTRACE_UPDATE_MODIFY_CALL:
397 ftrace_addr = get_ftrace_old_addr(rec);
398
399 case FTRACE_UPDATE_MAKE_NOP:
400
401 return add_brk_on_call(rec, ftrace_addr);
402 }
403 return 0;
404}
405
406
407
408
409
410
411
412
413
414static int remove_breakpoint(struct dyn_ftrace *rec)
415{
416 unsigned char ins[MCOUNT_INSN_SIZE];
417 unsigned char brk = BREAKPOINT_INSTRUCTION;
418 const unsigned char *nop;
419 unsigned long ftrace_addr;
420 unsigned long ip = rec->ip;
421
422
423 if (probe_kernel_read(ins, (void *)ip, MCOUNT_INSN_SIZE))
424 return -EFAULT;
425
426
427 if (ins[0] != brk)
428 return 0;
429
430 nop = ftrace_nop_replace();
431
432
433
434
435
436 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) {
437
438
439
440
441
442
443 ftrace_addr = get_ftrace_addr(rec);
444 nop = ftrace_call_replace(ip, ftrace_addr);
445
446 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
447 goto update;
448
449
450 ftrace_addr = get_ftrace_old_addr(rec);
451 nop = ftrace_call_replace(ip, ftrace_addr);
452
453 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
454 return -EINVAL;
455 }
456
457 update:
458 return ftrace_write(ip, nop, 1);
459}
460
461static int add_update_code(unsigned long ip, unsigned const char *new)
462{
463
464 ip++;
465 new++;
466 return ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1);
467}
468
469static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
470{
471 unsigned long ip = rec->ip;
472 unsigned const char *new;
473
474 new = ftrace_call_replace(ip, addr);
475 return add_update_code(ip, new);
476}
477
478static int add_update_nop(struct dyn_ftrace *rec)
479{
480 unsigned long ip = rec->ip;
481 unsigned const char *new;
482
483 new = ftrace_nop_replace();
484 return add_update_code(ip, new);
485}
486
487static int add_update(struct dyn_ftrace *rec, int enable)
488{
489 unsigned long ftrace_addr;
490 int ret;
491
492 ret = ftrace_test_record(rec, enable);
493
494 ftrace_addr = get_ftrace_addr(rec);
495
496 switch (ret) {
497 case FTRACE_UPDATE_IGNORE:
498 return 0;
499
500 case FTRACE_UPDATE_MODIFY_CALL_REGS:
501 case FTRACE_UPDATE_MODIFY_CALL:
502 case FTRACE_UPDATE_MAKE_CALL:
503
504 return add_update_call(rec, ftrace_addr);
505
506 case FTRACE_UPDATE_MAKE_NOP:
507
508 return add_update_nop(rec);
509 }
510
511 return 0;
512}
513
514static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
515{
516 unsigned long ip = rec->ip;
517 unsigned const char *new;
518
519 new = ftrace_call_replace(ip, addr);
520
521 return ftrace_write(ip, new, 1);
522}
523
524static int finish_update_nop(struct dyn_ftrace *rec)
525{
526 unsigned long ip = rec->ip;
527 unsigned const char *new;
528
529 new = ftrace_nop_replace();
530
531 return ftrace_write(ip, new, 1);
532}
533
534static int finish_update(struct dyn_ftrace *rec, int enable)
535{
536 unsigned long ftrace_addr;
537 int ret;
538
539 ret = ftrace_update_record(rec, enable);
540
541 ftrace_addr = get_ftrace_addr(rec);
542
543 switch (ret) {
544 case FTRACE_UPDATE_IGNORE:
545 return 0;
546
547 case FTRACE_UPDATE_MODIFY_CALL_REGS:
548 case FTRACE_UPDATE_MODIFY_CALL:
549 case FTRACE_UPDATE_MAKE_CALL:
550
551 return finish_update_call(rec, ftrace_addr);
552
553 case FTRACE_UPDATE_MAKE_NOP:
554
555 return finish_update_nop(rec);
556 }
557
558 return 0;
559}
560
561static void do_sync_core(void *data)
562{
563 sync_core();
564}
565
566static void run_sync(void)
567{
568 int enable_irqs = irqs_disabled();
569
570
571 if (enable_irqs)
572 local_irq_enable();
573 on_each_cpu(do_sync_core, NULL, 1);
574 if (enable_irqs)
575 local_irq_disable();
576}
577
578void ftrace_replace_code(int enable)
579{
580 struct ftrace_rec_iter *iter;
581 struct dyn_ftrace *rec;
582 const char *report = "adding breakpoints";
583 int count = 0;
584 int ret;
585
586 for_ftrace_rec_iter(iter) {
587 rec = ftrace_rec_iter_record(iter);
588
589 ret = add_breakpoints(rec, enable);
590 if (ret)
591 goto remove_breakpoints;
592 count++;
593 }
594
595 run_sync();
596
597 report = "updating code";
598
599 for_ftrace_rec_iter(iter) {
600 rec = ftrace_rec_iter_record(iter);
601
602 ret = add_update(rec, enable);
603 if (ret)
604 goto remove_breakpoints;
605 }
606
607 run_sync();
608
609 report = "removing breakpoints";
610
611 for_ftrace_rec_iter(iter) {
612 rec = ftrace_rec_iter_record(iter);
613
614 ret = finish_update(rec, enable);
615 if (ret)
616 goto remove_breakpoints;
617 }
618
619 run_sync();
620
621 return;
622
623 remove_breakpoints:
624 ftrace_bug(ret, rec ? rec->ip : 0);
625 printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
626 for_ftrace_rec_iter(iter) {
627 rec = ftrace_rec_iter_record(iter);
628
629
630
631
632 if (remove_breakpoint(rec))
633 BUG();
634 }
635 run_sync();
636}
637
638static int
639ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
640 unsigned const char *new_code)
641{
642 int ret;
643
644 ret = add_break(ip, old_code);
645 if (ret)
646 goto out;
647
648 run_sync();
649
650 ret = add_update_code(ip, new_code);
651 if (ret)
652 goto fail_update;
653
654 run_sync();
655
656 ret = ftrace_write(ip, new_code, 1);
657
658
659
660
661 BUG_ON(ret);
662 out:
663 run_sync();
664 return ret;
665
666 fail_update:
667
668 if (ftrace_write(ip, old_code, 1))
669 BUG();
670 goto out;
671}
672
673void arch_ftrace_update_code(int command)
674{
675
676 atomic_inc(&modifying_ftrace_code);
677
678 ftrace_modify_all_code(command);
679
680 atomic_dec(&modifying_ftrace_code);
681}
682
683int __init ftrace_dyn_arch_init(void *data)
684{
685
686 *(unsigned long *)data = 0;
687
688 return 0;
689}
690#endif
691
692#ifdef CONFIG_FUNCTION_GRAPH_TRACER
693
694#ifdef CONFIG_DYNAMIC_FTRACE
695extern void ftrace_graph_call(void);
696
697static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
698{
699 static union ftrace_code_union calc;
700
701
702 calc.e8 = 0xe9;
703 calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
704
705
706
707
708 return calc.code;
709}
710
711static int ftrace_mod_jmp(unsigned long ip, void *func)
712{
713 unsigned char *new;
714
715 new = ftrace_jmp_replace(ip, (unsigned long)func);
716
717 return update_ftrace_func(ip, new);
718}
719
720int ftrace_enable_ftrace_graph_caller(void)
721{
722 unsigned long ip = (unsigned long)(&ftrace_graph_call);
723
724 return ftrace_mod_jmp(ip, &ftrace_graph_caller);
725}
726
727int ftrace_disable_ftrace_graph_caller(void)
728{
729 unsigned long ip = (unsigned long)(&ftrace_graph_call);
730
731 return ftrace_mod_jmp(ip, &ftrace_stub);
732}
733
734#endif
735
736
737
738
739
740void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
741 unsigned long frame_pointer)
742{
743 unsigned long old;
744 int faulted;
745 struct ftrace_graph_ent trace;
746 unsigned long return_hooker = (unsigned long)
747 &return_to_handler;
748
749 if (unlikely(ftrace_graph_is_dead()))
750 return;
751
752 if (unlikely(atomic_read(¤t->tracing_graph_pause)))
753 return;
754
755
756
757
758
759
760 asm volatile(
761 "1: " _ASM_MOV " (%[parent]), %[old]\n"
762 "2: " _ASM_MOV " %[return_hooker], (%[parent])\n"
763 " movl $0, %[faulted]\n"
764 "3:\n"
765
766 ".section .fixup, \"ax\"\n"
767 "4: movl $1, %[faulted]\n"
768 " jmp 3b\n"
769 ".previous\n"
770
771 _ASM_EXTABLE(1b, 4b)
772 _ASM_EXTABLE(2b, 4b)
773
774 : [old] "=&r" (old), [faulted] "=r" (faulted)
775 : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
776 : "memory"
777 );
778
779 if (unlikely(faulted)) {
780 ftrace_graph_stop();
781 WARN_ON(1);
782 return;
783 }
784
785 trace.func = self_addr;
786 trace.depth = current->curr_ret_stack + 1;
787
788
789 if (!ftrace_graph_entry(&trace)) {
790 *parent = old;
791 return;
792 }
793
794 if (ftrace_push_return_trace(old, self_addr, &trace.depth,
795 frame_pointer, parent) == -EBUSY) {
796 *parent = old;
797 return;
798 }
799}
800#endif
801