aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/ftrace.c')
-rw-r--r--arch/x86/kernel/ftrace.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 7ee8067cbf45..8257a59704ae 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -733,18 +733,20 @@ union ftrace_op_code_union {
733 } __attribute__((packed)); 733 } __attribute__((packed));
734}; 734};
735 735
736#define RET_SIZE 1
737
736static unsigned long 738static unsigned long
737create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) 739create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
738{ 740{
739 unsigned const char *jmp;
740 unsigned long start_offset; 741 unsigned long start_offset;
741 unsigned long end_offset; 742 unsigned long end_offset;
742 unsigned long op_offset; 743 unsigned long op_offset;
743 unsigned long offset; 744 unsigned long offset;
744 unsigned long size; 745 unsigned long size;
745 unsigned long ip; 746 unsigned long retq;
746 unsigned long *ptr; 747 unsigned long *ptr;
747 void *trampoline; 748 void *trampoline;
749 void *ip;
748 /* 48 8b 15 <offset> is movq <offset>(%rip), %rdx */ 750 /* 48 8b 15 <offset> is movq <offset>(%rip), %rdx */
749 unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 }; 751 unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
750 union ftrace_op_code_union op_ptr; 752 union ftrace_op_code_union op_ptr;
@@ -764,27 +766,27 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
764 766
765 /* 767 /*
766 * Allocate enough size to store the ftrace_caller code, 768 * Allocate enough size to store the ftrace_caller code,
767 * the jmp to ftrace_epilogue, as well as the address of 769 * the iret , as well as the address of the ftrace_ops this
768 * the ftrace_ops this trampoline is used for. 770 * trampoline is used for.
769 */ 771 */
770 trampoline = alloc_tramp(size + MCOUNT_INSN_SIZE + sizeof(void *)); 772 trampoline = alloc_tramp(size + RET_SIZE + sizeof(void *));
771 if (!trampoline) 773 if (!trampoline)
772 return 0; 774 return 0;
773 775
774 *tramp_size = size + MCOUNT_INSN_SIZE + sizeof(void *); 776 *tramp_size = size + RET_SIZE + sizeof(void *);
775 777
776 /* Copy ftrace_caller onto the trampoline memory */ 778 /* Copy ftrace_caller onto the trampoline memory */
777 ret = probe_kernel_read(trampoline, (void *)start_offset, size); 779 ret = probe_kernel_read(trampoline, (void *)start_offset, size);
778 if (WARN_ON(ret < 0)) { 780 if (WARN_ON(ret < 0))
779 tramp_free(trampoline, *tramp_size); 781 goto fail;
780 return 0;
781 }
782 782
783 ip = (unsigned long)trampoline + size; 783 ip = trampoline + size;
784 784
785 /* The trampoline ends with a jmp to ftrace_epilogue */ 785 /* The trampoline ends with ret(q) */
786 jmp = ftrace_jmp_replace(ip, (unsigned long)ftrace_epilogue); 786 retq = (unsigned long)ftrace_stub;
787 memcpy(trampoline + size, jmp, MCOUNT_INSN_SIZE); 787 ret = probe_kernel_read(ip, (void *)retq, RET_SIZE);
788 if (WARN_ON(ret < 0))
789 goto fail;
788 790
789 /* 791 /*
790 * The address of the ftrace_ops that is used for this trampoline 792 * The address of the ftrace_ops that is used for this trampoline
@@ -794,17 +796,15 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
794 * the global function_trace_op variable. 796 * the global function_trace_op variable.
795 */ 797 */
796 798
797 ptr = (unsigned long *)(trampoline + size + MCOUNT_INSN_SIZE); 799 ptr = (unsigned long *)(trampoline + size + RET_SIZE);
798 *ptr = (unsigned long)ops; 800 *ptr = (unsigned long)ops;
799 801
800 op_offset -= start_offset; 802 op_offset -= start_offset;
801 memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE); 803 memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
802 804
803 /* Are we pointing to the reference? */ 805 /* Are we pointing to the reference? */
804 if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) { 806 if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0))
805 tramp_free(trampoline, *tramp_size); 807 goto fail;
806 return 0;
807 }
808 808
809 /* Load the contents of ptr into the callback parameter */ 809 /* Load the contents of ptr into the callback parameter */
810 offset = (unsigned long)ptr; 810 offset = (unsigned long)ptr;
@@ -819,6 +819,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
819 ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP; 819 ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
820 820
821 return (unsigned long)trampoline; 821 return (unsigned long)trampoline;
822fail:
823 tramp_free(trampoline, *tramp_size);
824 return 0;
822} 825}
823 826
824static unsigned long calc_trampoline_call_offset(bool save_regs) 827static unsigned long calc_trampoline_call_offset(bool save_regs)