@@ -48,7 +48,7 @@ int ftrace_arch_code_modify_post_process(void)
4848union ftrace_code_union {
4949 char code [MCOUNT_INSN_SIZE ];
5050 struct {
51- char e8 ;
51+ unsigned char e8 ;
5252 int offset ;
5353 } __attribute__((packed ));
5454};
@@ -797,12 +797,26 @@ static unsigned long create_trampoline(struct ftrace_ops *ops)
797797 return (unsigned long )trampoline ;
798798}
799799
800+ static unsigned long calc_trampoline_call_offset (bool save_regs )
801+ {
802+ unsigned long start_offset ;
803+ unsigned long call_offset ;
804+
805+ if (save_regs ) {
806+ start_offset = (unsigned long )ftrace_regs_caller ;
807+ call_offset = (unsigned long )ftrace_regs_call ;
808+ } else {
809+ start_offset = (unsigned long )ftrace_caller ;
810+ call_offset = (unsigned long )ftrace_call ;
811+ }
812+
813+ return call_offset - start_offset ;
814+ }
815+
800816void arch_ftrace_update_trampoline (struct ftrace_ops * ops )
801817{
802818 ftrace_func_t func ;
803819 unsigned char * new ;
804- unsigned long start_offset ;
805- unsigned long call_offset ;
806820 unsigned long offset ;
807821 unsigned long ip ;
808822 int ret ;
@@ -820,15 +834,7 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
820834 return ;
821835 }
822836
823- if (ops -> flags & FTRACE_OPS_FL_SAVE_REGS ) {
824- start_offset = (unsigned long )ftrace_regs_caller ;
825- call_offset = (unsigned long )ftrace_regs_call ;
826- } else {
827- start_offset = (unsigned long )ftrace_caller ;
828- call_offset = (unsigned long )ftrace_call ;
829- }
830-
831- offset = call_offset - start_offset ;
837+ offset = calc_trampoline_call_offset (ops -> flags & FTRACE_OPS_FL_SAVE_REGS );
832838 ip = ops -> trampoline + offset ;
833839
834840 func = ftrace_ops_get_func (ops );
@@ -840,6 +846,74 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
840846 /* The update should never fail */
841847 WARN_ON (ret );
842848}
849+
850+ /* Return the address of the function the trampoline calls */
851+ static void * addr_from_call (void * ptr )
852+ {
853+ union ftrace_code_union calc ;
854+ int ret ;
855+
856+ ret = probe_kernel_read (& calc , ptr , MCOUNT_INSN_SIZE );
857+ if (WARN_ON_ONCE (ret < 0 ))
858+ return NULL ;
859+
860+ /* Make sure this is a call */
861+ if (WARN_ON_ONCE (calc .e8 != 0xe8 )) {
862+ pr_warn ("Expected e8, got %x\n" , calc .e8 );
863+ return NULL ;
864+ }
865+
866+ return ptr + MCOUNT_INSN_SIZE + calc .offset ;
867+ }
868+
869+ void prepare_ftrace_return (unsigned long * parent , unsigned long self_addr ,
870+ unsigned long frame_pointer );
871+
872+ /*
873+ * If the ops->trampoline was not allocated, then it probably
874+ * has a static trampoline func, or is the ftrace caller itself.
875+ */
876+ static void * static_tramp_func (struct ftrace_ops * ops , struct dyn_ftrace * rec )
877+ {
878+ unsigned long offset ;
879+ bool save_regs = rec -> flags & FTRACE_FL_REGS_EN ;
880+ void * ptr ;
881+
882+ if (ops && ops -> trampoline ) {
883+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
884+ /*
885+ * We only know about function graph tracer setting as static
886+ * trampoline.
887+ */
888+ if (ops -> trampoline == FTRACE_GRAPH_ADDR )
889+ return (void * )prepare_ftrace_return ;
890+ #endif
891+ return NULL ;
892+ }
893+
894+ offset = calc_trampoline_call_offset (save_regs );
895+
896+ if (save_regs )
897+ ptr = (void * )FTRACE_REGS_ADDR + offset ;
898+ else
899+ ptr = (void * )FTRACE_ADDR + offset ;
900+
901+ return addr_from_call (ptr );
902+ }
903+
904+ void * arch_ftrace_trampoline_func (struct ftrace_ops * ops , struct dyn_ftrace * rec )
905+ {
906+ unsigned long offset ;
907+
908+ /* If we didn't allocate this trampoline, consider it static */
909+ if (!ops || !(ops -> flags & FTRACE_OPS_FL_ALLOC_TRAMP ))
910+ return static_tramp_func (ops , rec );
911+
912+ offset = calc_trampoline_call_offset (ops -> flags & FTRACE_OPS_FL_SAVE_REGS );
913+ return addr_from_call ((void * )ops -> trampoline + offset );
914+ }
915+
916+
843917#endif /* CONFIG_X86_64 */
844918#endif /* CONFIG_DYNAMIC_FTRACE */
845919
0 commit comments