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/slab.h>
21#include <linux/init.h>
22#include <linux/list.h>
23#include <linux/module.h>
24
25#include <trace/syscall.h>
26
27#include <asm/cacheflush.h>
28#include <asm/kprobes.h>
29#include <asm/ftrace.h>
30#include <asm/nops.h>
31
32#ifdef CONFIG_DYNAMIC_FTRACE
33
34int ftrace_arch_code_modify_prepare(void)
35{
36 set_kernel_text_rw();
37 set_all_modules_text_rw();
38 return 0;
39}
40
41int ftrace_arch_code_modify_post_process(void)
42{
43 set_all_modules_text_ro();
44 set_kernel_text_ro();
45 return 0;
46}
47
48union ftrace_code_union {
49 char code[MCOUNT_INSN_SIZE];
50 struct {
51 unsigned char e8;
52 int offset;
53 } __attribute__((packed));
54};
55
56static int ftrace_calc_offset(long ip, long addr)
57{
58 return (int)(addr - ip);
59}
60
61static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
62{
63 static union ftrace_code_union calc;
64
65 calc.e8 = 0xe8;
66 calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
67
68
69
70
71
72 return calc.code;
73}
74
75static inline int
76within(unsigned long addr, unsigned long start, unsigned long end)
77{
78 return addr >= start && addr < end;
79}
80
81static unsigned long text_ip_addr(unsigned long ip)
82{
83
84
85
86
87
88
89
90
91 if (within(ip, (unsigned long)_text, (unsigned long)_etext))
92 ip = (unsigned long)__va(__pa_symbol(ip));
93
94 return ip;
95}
96
97static const unsigned char *ftrace_nop_replace(void)
98{
99 return ideal_nops[NOP_ATOMIC5];
100}
101
102static int
103ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
104 unsigned const char *new_code)
105{
106 unsigned char replaced[MCOUNT_INSN_SIZE];
107
108 ftrace_expected = old_code;
109
110
111
112
113
114
115
116
117
118
119 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
120 return -EFAULT;
121
122
123 if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
124 return -EINVAL;
125
126 ip = text_ip_addr(ip);
127
128
129 if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
130 return -EPERM;
131
132 sync_core();
133
134 return 0;
135}
136
137int ftrace_make_nop(struct module *mod,
138 struct dyn_ftrace *rec, unsigned long addr)
139{
140 unsigned const char *new, *old;
141 unsigned long ip = rec->ip;
142
143 old = ftrace_call_replace(ip, addr);
144 new = ftrace_nop_replace();
145
146
147
148
149
150
151
152
153
154 if (addr == MCOUNT_ADDR)
155 return ftrace_modify_code_direct(rec->ip, old, new);
156
157 ftrace_expected = NULL;
158
159
160 WARN_ONCE(1, "invalid use of ftrace_make_nop");
161 return -EINVAL;
162}
163
164int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
165{
166 unsigned const char *new, *old;
167 unsigned long ip = rec->ip;
168
169 old = ftrace_nop_replace();
170 new = ftrace_call_replace(ip, addr);
171
172
173 return ftrace_modify_code_direct(rec->ip, old, new);
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
204
205
206
207atomic_t modifying_ftrace_code __read_mostly;
208
209static int
210ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
211 unsigned const char *new_code);
212
213
214
215
216
217
218
219
220
221int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
222 unsigned long addr)
223{
224 WARN_ON(1);
225 ftrace_expected = NULL;
226 return -EINVAL;
227}
228
229static unsigned long ftrace_update_func;
230
231static int update_ftrace_func(unsigned long ip, void *new)
232{
233 unsigned char old[MCOUNT_INSN_SIZE];
234 int ret;
235
236 memcpy(old, (void *)ip, MCOUNT_INSN_SIZE);
237
238 ftrace_update_func = ip;
239
240 smp_wmb();
241
242
243 atomic_inc(&modifying_ftrace_code);
244
245 ret = ftrace_modify_code(ip, old, new);
246
247 atomic_dec(&modifying_ftrace_code);
248
249 return ret;
250}
251
252int ftrace_update_ftrace_func(ftrace_func_t func)
253{
254 unsigned long ip = (unsigned long)(&ftrace_call);
255 unsigned char *new;
256 int ret;
257
258 new = ftrace_call_replace(ip, (unsigned long)func);
259 ret = update_ftrace_func(ip, new);
260
261
262 if (!ret) {
263 ip = (unsigned long)(&ftrace_regs_call);
264 new = ftrace_call_replace(ip, (unsigned long)func);
265 ret = update_ftrace_func(ip, new);
266 }
267
268 return ret;
269}
270
271static int is_ftrace_caller(unsigned long ip)
272{
273 if (ip == ftrace_update_func)
274 return 1;
275
276 return 0;
277}
278
279
280
281
282
283
284
285
286int ftrace_int3_handler(struct pt_regs *regs)
287{
288 unsigned long ip;
289
290 if (WARN_ON_ONCE(!regs))
291 return 0;
292
293 ip = regs->ip - 1;
294 if (!ftrace_location(ip) && !is_ftrace_caller(ip))
295 return 0;
296
297 regs->ip += MCOUNT_INSN_SIZE - 1;
298
299 return 1;
300}
301
302static int ftrace_write(unsigned long ip, const char *val, int size)
303{
304 ip = text_ip_addr(ip);
305
306 if (probe_kernel_write((void *)ip, val, size))
307 return -EPERM;
308
309 return 0;
310}
311
312static int add_break(unsigned long ip, const char *old)
313{
314 unsigned char replaced[MCOUNT_INSN_SIZE];
315 unsigned char brk = BREAKPOINT_INSTRUCTION;
316
317 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
318 return -EFAULT;
319
320 ftrace_expected = old;
321
322
323 if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
324 return -EINVAL;
325
326 return ftrace_write(ip, &brk, 1);
327}
328
329static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
330{
331 unsigned const char *old;
332 unsigned long ip = rec->ip;
333
334 old = ftrace_call_replace(ip, addr);
335
336 return add_break(rec->ip, old);
337}
338
339
340static int add_brk_on_nop(struct dyn_ftrace *rec)
341{
342 unsigned const char *old;
343
344 old = ftrace_nop_replace();
345
346 return add_break(rec->ip, old);
347}
348
349static int add_breakpoints(struct dyn_ftrace *rec, int enable)
350{
351 unsigned long ftrace_addr;
352 int ret;
353
354 ftrace_addr = ftrace_get_addr_curr(rec);
355
356 ret = ftrace_test_record(rec, enable);
357
358 switch (ret) {
359 case FTRACE_UPDATE_IGNORE:
360 return 0;
361
362 case FTRACE_UPDATE_MAKE_CALL:
363
364 return add_brk_on_nop(rec);
365
366 case FTRACE_UPDATE_MODIFY_CALL:
367 case FTRACE_UPDATE_MAKE_NOP:
368
369 return add_brk_on_call(rec, ftrace_addr);
370 }
371 return 0;
372}
373
374
375
376
377
378
379
380
381
382static int remove_breakpoint(struct dyn_ftrace *rec)
383{
384 unsigned char ins[MCOUNT_INSN_SIZE];
385 unsigned char brk = BREAKPOINT_INSTRUCTION;
386 const unsigned char *nop;
387 unsigned long ftrace_addr;
388 unsigned long ip = rec->ip;
389
390
391 if (probe_kernel_read(ins, (void *)ip, MCOUNT_INSN_SIZE))
392 return -EFAULT;
393
394
395 if (ins[0] != brk)
396 return 0;
397
398 nop = ftrace_nop_replace();
399
400
401
402
403
404 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) {
405
406
407
408
409
410
411 ftrace_addr = ftrace_get_addr_new(rec);
412 nop = ftrace_call_replace(ip, ftrace_addr);
413
414 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
415 goto update;
416
417
418 ftrace_addr = ftrace_get_addr_curr(rec);
419 nop = ftrace_call_replace(ip, ftrace_addr);
420
421 ftrace_expected = nop;
422
423 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
424 return -EINVAL;
425 }
426
427 update:
428 return ftrace_write(ip, nop, 1);
429}
430
431static int add_update_code(unsigned long ip, unsigned const char *new)
432{
433
434 ip++;
435 new++;
436 return ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1);
437}
438
439static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
440{
441 unsigned long ip = rec->ip;
442 unsigned const char *new;
443
444 new = ftrace_call_replace(ip, addr);
445 return add_update_code(ip, new);
446}
447
448static int add_update_nop(struct dyn_ftrace *rec)
449{
450 unsigned long ip = rec->ip;
451 unsigned const char *new;
452
453 new = ftrace_nop_replace();
454 return add_update_code(ip, new);
455}
456
457static int add_update(struct dyn_ftrace *rec, int enable)
458{
459 unsigned long ftrace_addr;
460 int ret;
461
462 ret = ftrace_test_record(rec, enable);
463
464 ftrace_addr = ftrace_get_addr_new(rec);
465
466 switch (ret) {
467 case FTRACE_UPDATE_IGNORE:
468 return 0;
469
470 case FTRACE_UPDATE_MODIFY_CALL:
471 case FTRACE_UPDATE_MAKE_CALL:
472
473 return add_update_call(rec, ftrace_addr);
474
475 case FTRACE_UPDATE_MAKE_NOP:
476
477 return add_update_nop(rec);
478 }
479
480 return 0;
481}
482
483static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
484{
485 unsigned long ip = rec->ip;
486 unsigned const char *new;
487
488 new = ftrace_call_replace(ip, addr);
489
490 return ftrace_write(ip, new, 1);
491}
492
493static int finish_update_nop(struct dyn_ftrace *rec)
494{
495 unsigned long ip = rec->ip;
496 unsigned const char *new;
497
498 new = ftrace_nop_replace();
499
500 return ftrace_write(ip, new, 1);
501}
502
503static int finish_update(struct dyn_ftrace *rec, int enable)
504{
505 unsigned long ftrace_addr;
506 int ret;
507
508 ret = ftrace_update_record(rec, enable);
509
510 ftrace_addr = ftrace_get_addr_new(rec);
511
512 switch (ret) {
513 case FTRACE_UPDATE_IGNORE:
514 return 0;
515
516 case FTRACE_UPDATE_MODIFY_CALL:
517 case FTRACE_UPDATE_MAKE_CALL:
518
519 return finish_update_call(rec, ftrace_addr);
520
521 case FTRACE_UPDATE_MAKE_NOP:
522
523 return finish_update_nop(rec);
524 }
525
526 return 0;
527}
528
529static void do_sync_core(void *data)
530{
531 sync_core();
532}
533
534static void run_sync(void)
535{
536 int enable_irqs = irqs_disabled();
537
538
539 if (enable_irqs)
540 local_irq_enable();
541 on_each_cpu(do_sync_core, NULL, 1);
542 if (enable_irqs)
543 local_irq_disable();
544}
545
546void ftrace_replace_code(int enable)
547{
548 struct ftrace_rec_iter *iter;
549 struct dyn_ftrace *rec;
550 const char *report = "adding breakpoints";
551 int count = 0;
552 int ret;
553
554 for_ftrace_rec_iter(iter) {
555 rec = ftrace_rec_iter_record(iter);
556
557 ret = add_breakpoints(rec, enable);
558 if (ret)
559 goto remove_breakpoints;
560 count++;
561 }
562
563 run_sync();
564
565 report = "updating code";
566 count = 0;
567
568 for_ftrace_rec_iter(iter) {
569 rec = ftrace_rec_iter_record(iter);
570
571 ret = add_update(rec, enable);
572 if (ret)
573 goto remove_breakpoints;
574 count++;
575 }
576
577 run_sync();
578
579 report = "removing breakpoints";
580 count = 0;
581
582 for_ftrace_rec_iter(iter) {
583 rec = ftrace_rec_iter_record(iter);
584
585 ret = finish_update(rec, enable);
586 if (ret)
587 goto remove_breakpoints;
588 count++;
589 }
590
591 run_sync();
592
593 return;
594
595 remove_breakpoints:
596 pr_warn("Failed on %s (%d):\n", report, count);
597 ftrace_bug(ret, rec);
598 for_ftrace_rec_iter(iter) {
599 rec = ftrace_rec_iter_record(iter);
600
601
602
603
604 if (remove_breakpoint(rec))
605 BUG();
606 }
607 run_sync();
608}
609
610static int
611ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
612 unsigned const char *new_code)
613{
614 int ret;
615
616 ret = add_break(ip, old_code);
617 if (ret)
618 goto out;
619
620 run_sync();
621
622 ret = add_update_code(ip, new_code);
623 if (ret)
624 goto fail_update;
625
626 run_sync();
627
628 ret = ftrace_write(ip, new_code, 1);
629
630
631
632
633 BUG_ON(ret);
634 out:
635 run_sync();
636 return ret;
637
638 fail_update:
639
640 if (ftrace_write(ip, old_code, 1))
641 BUG();
642 goto out;
643}
644
645void arch_ftrace_update_code(int command)
646{
647
648 atomic_inc(&modifying_ftrace_code);
649
650 ftrace_modify_all_code(command);
651
652 atomic_dec(&modifying_ftrace_code);
653}
654
655int __init ftrace_dyn_arch_init(void)
656{
657 return 0;
658}
659
660#if defined(CONFIG_X86_64) || defined(CONFIG_FUNCTION_GRAPH_TRACER)
661static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
662{
663 static union ftrace_code_union calc;
664
665
666 calc.e8 = 0xe9;
667 calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
668
669
670
671
672 return calc.code;
673}
674#endif
675
676
677#ifdef CONFIG_X86_64
678
679#ifdef CONFIG_MODULES
680#include <linux/moduleloader.h>
681
682static inline void *alloc_tramp(unsigned long size)
683{
684 return module_alloc(size);
685}
686static inline void tramp_free(void *tramp)
687{
688 module_memfree(tramp);
689}
690#else
691
692static inline void *alloc_tramp(unsigned long size)
693{
694 return NULL;
695}
696static inline void tramp_free(void *tramp) { }
697#endif
698
699
700extern void ftrace_regs_caller_end(void);
701extern void ftrace_epilogue(void);
702extern void ftrace_caller_op_ptr(void);
703extern void ftrace_regs_caller_op_ptr(void);
704
705
706
707#define OP_REF_SIZE 7
708
709
710
711
712
713
714
715
716
717union ftrace_op_code_union {
718 char code[OP_REF_SIZE];
719 struct {
720 char op[3];
721 int offset;
722 } __attribute__((packed));
723};
724
725static unsigned long
726create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
727{
728 unsigned const char *jmp;
729 unsigned long start_offset;
730 unsigned long end_offset;
731 unsigned long op_offset;
732 unsigned long offset;
733 unsigned long size;
734 unsigned long ip;
735 unsigned long *ptr;
736 void *trampoline;
737
738 unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
739 union ftrace_op_code_union op_ptr;
740 int ret;
741
742 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
743 start_offset = (unsigned long)ftrace_regs_caller;
744 end_offset = (unsigned long)ftrace_regs_caller_end;
745 op_offset = (unsigned long)ftrace_regs_caller_op_ptr;
746 } else {
747 start_offset = (unsigned long)ftrace_caller;
748 end_offset = (unsigned long)ftrace_epilogue;
749 op_offset = (unsigned long)ftrace_caller_op_ptr;
750 }
751
752 size = end_offset - start_offset;
753
754
755
756
757
758
759 trampoline = alloc_tramp(size + MCOUNT_INSN_SIZE + sizeof(void *));
760 if (!trampoline)
761 return 0;
762
763 *tramp_size = size + MCOUNT_INSN_SIZE + sizeof(void *);
764
765
766 ret = probe_kernel_read(trampoline, (void *)start_offset, size);
767 if (WARN_ON(ret < 0)) {
768 tramp_free(trampoline);
769 return 0;
770 }
771
772 ip = (unsigned long)trampoline + size;
773
774
775 jmp = ftrace_jmp_replace(ip, (unsigned long)ftrace_epilogue);
776 memcpy(trampoline + size, jmp, MCOUNT_INSN_SIZE);
777
778
779
780
781
782
783
784
785
786 ptr = (unsigned long *)(trampoline + size + MCOUNT_INSN_SIZE);
787 *ptr = (unsigned long)ops;
788
789 op_offset -= start_offset;
790 memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
791
792
793 if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) {
794 tramp_free(trampoline);
795 return 0;
796 }
797
798
799 offset = (unsigned long)ptr;
800 offset -= (unsigned long)trampoline + op_offset + OP_REF_SIZE;
801
802 op_ptr.offset = offset;
803
804
805 memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
806
807
808 ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
809
810 return (unsigned long)trampoline;
811}
812
813static unsigned long calc_trampoline_call_offset(bool save_regs)
814{
815 unsigned long start_offset;
816 unsigned long call_offset;
817
818 if (save_regs) {
819 start_offset = (unsigned long)ftrace_regs_caller;
820 call_offset = (unsigned long)ftrace_regs_call;
821 } else {
822 start_offset = (unsigned long)ftrace_caller;
823 call_offset = (unsigned long)ftrace_call;
824 }
825
826 return call_offset - start_offset;
827}
828
829void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
830{
831 ftrace_func_t func;
832 unsigned char *new;
833 unsigned long offset;
834 unsigned long ip;
835 unsigned int size;
836 int ret;
837
838 if (ops->trampoline) {
839
840
841
842
843 if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
844 return;
845 } else {
846 ops->trampoline = create_trampoline(ops, &size);
847 if (!ops->trampoline)
848 return;
849 ops->trampoline_size = size;
850 }
851
852 offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
853 ip = ops->trampoline + offset;
854
855 func = ftrace_ops_get_func(ops);
856
857
858 new = ftrace_call_replace(ip, (unsigned long)func);
859 ret = update_ftrace_func(ip, new);
860
861
862 WARN_ON(ret);
863}
864
865
866static void *addr_from_call(void *ptr)
867{
868 union ftrace_code_union calc;
869 int ret;
870
871 ret = probe_kernel_read(&calc, ptr, MCOUNT_INSN_SIZE);
872 if (WARN_ON_ONCE(ret < 0))
873 return NULL;
874
875
876 if (WARN_ON_ONCE(calc.e8 != 0xe8)) {
877 pr_warn("Expected e8, got %x\n", calc.e8);
878 return NULL;
879 }
880
881 return ptr + MCOUNT_INSN_SIZE + calc.offset;
882}
883
884void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
885 unsigned long frame_pointer);
886
887
888
889
890
891static void *static_tramp_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
892{
893 unsigned long offset;
894 bool save_regs = rec->flags & FTRACE_FL_REGS_EN;
895 void *ptr;
896
897 if (ops && ops->trampoline) {
898#ifdef CONFIG_FUNCTION_GRAPH_TRACER
899
900
901
902
903 if (ops->trampoline == FTRACE_GRAPH_ADDR)
904 return (void *)prepare_ftrace_return;
905#endif
906 return NULL;
907 }
908
909 offset = calc_trampoline_call_offset(save_regs);
910
911 if (save_regs)
912 ptr = (void *)FTRACE_REGS_ADDR + offset;
913 else
914 ptr = (void *)FTRACE_ADDR + offset;
915
916 return addr_from_call(ptr);
917}
918
919void *arch_ftrace_trampoline_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
920{
921 unsigned long offset;
922
923
924 if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
925 return static_tramp_func(ops, rec);
926
927 offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
928 return addr_from_call((void *)ops->trampoline + offset);
929}
930
931void arch_ftrace_trampoline_free(struct ftrace_ops *ops)
932{
933 if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
934 return;
935
936 tramp_free((void *)ops->trampoline);
937 ops->trampoline = 0;
938}
939
940#endif
941#endif
942
943#ifdef CONFIG_FUNCTION_GRAPH_TRACER
944
945#ifdef CONFIG_DYNAMIC_FTRACE
946extern void ftrace_graph_call(void);
947
948static int ftrace_mod_jmp(unsigned long ip, void *func)
949{
950 unsigned char *new;
951
952 new = ftrace_jmp_replace(ip, (unsigned long)func);
953
954 return update_ftrace_func(ip, new);
955}
956
957int ftrace_enable_ftrace_graph_caller(void)
958{
959 unsigned long ip = (unsigned long)(&ftrace_graph_call);
960
961 return ftrace_mod_jmp(ip, &ftrace_graph_caller);
962}
963
964int ftrace_disable_ftrace_graph_caller(void)
965{
966 unsigned long ip = (unsigned long)(&ftrace_graph_call);
967
968 return ftrace_mod_jmp(ip, &ftrace_stub);
969}
970
971#endif
972
973
974
975
976
977void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
978 unsigned long frame_pointer)
979{
980 unsigned long old;
981 int faulted;
982 struct ftrace_graph_ent trace;
983 unsigned long return_hooker = (unsigned long)
984 &return_to_handler;
985
986 if (unlikely(ftrace_graph_is_dead()))
987 return;
988
989 if (unlikely(atomic_read(¤t->tracing_graph_pause)))
990 return;
991
992
993
994
995
996
997 asm volatile(
998 "1: " _ASM_MOV " (%[parent]), %[old]\n"
999 "2: " _ASM_MOV " %[return_hooker], (%[parent])\n"
1000 " movl $0, %[faulted]\n"
1001 "3:\n"
1002
1003 ".section .fixup, \"ax\"\n"
1004 "4: movl $1, %[faulted]\n"
1005 " jmp 3b\n"
1006 ".previous\n"
1007
1008 _ASM_EXTABLE(1b, 4b)
1009 _ASM_EXTABLE(2b, 4b)
1010
1011 : [old] "=&r" (old), [faulted] "=r" (faulted)
1012 : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
1013 : "memory"
1014 );
1015
1016 if (unlikely(faulted)) {
1017 ftrace_graph_stop();
1018 WARN_ON(1);
1019 return;
1020 }
1021
1022 trace.func = self_addr;
1023 trace.depth = current->curr_ret_stack + 1;
1024
1025
1026 if (!ftrace_graph_entry(&trace)) {
1027 *parent = old;
1028 return;
1029 }
1030
1031 if (ftrace_push_return_trace(old, self_addr, &trace.depth,
1032 frame_pointer) == -EBUSY) {
1033 *parent = old;
1034 return;
1035 }
1036}
1037#endif
1038