aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-07-03 14:51:36 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-10-31 12:22:54 -0400
commit15d5b02cc575e5b20ddfa1645fc1242f0b0ba1c8 (patch)
tree92a2a3f35ac196354fc5c6dfa73f2b6af0d2d6d4
parentf3bea49115b21e0995abf41402ad2f4d9c69eda4 (diff)
ftrace/x86: Show trampoline call function in enabled_functions
The file /sys/kernel/debug/tracing/eneabled_functions is used to debug ftrace function hooks. Add to the output what function is being called by the trampoline if the arch supports it. Add support for this feature in x86_64. Cc: H. Peter Anvin <hpa@linux.intel.com> Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Tested-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/x86/kernel/ftrace.c98
-rw-r--r--kernel/trace/ftrace.c22
2 files changed, 106 insertions, 14 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index e4d48f6cad86..ca17c20a1010 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -48,7 +48,7 @@ int ftrace_arch_code_modify_post_process(void)
48union ftrace_code_union { 48union ftrace_code_union {
49 char code[MCOUNT_INSN_SIZE]; 49 char code[MCOUNT_INSN_SIZE];
50 struct { 50 struct {
51 char e8; 51 unsigned char e8;
52 int offset; 52 int offset;
53 } __attribute__((packed)); 53 } __attribute__((packed));
54}; 54};
@@ -797,12 +797,26 @@ static unsigned long create_trampoline(struct ftrace_ops *ops)
797 return (unsigned long)trampoline; 797 return (unsigned long)trampoline;
798} 798}
799 799
800static 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
800void arch_ftrace_update_trampoline(struct ftrace_ops *ops) 816void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
801{ 817{
802 ftrace_func_t func; 818 ftrace_func_t func;
803 unsigned char *new; 819 unsigned char *new;
804 unsigned long start_offset;
805 unsigned long call_offset;
806 unsigned long offset; 820 unsigned long offset;
807 unsigned long ip; 821 unsigned long ip;
808 int ret; 822 int ret;
@@ -820,15 +834,7 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
820 return; 834 return;
821 } 835 }
822 836
823 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) { 837 offset = calc_trampoline_call_offset(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;
832 ip = ops->trampoline + offset; 838 ip = ops->trampoline + offset;
833 839
834 func = ftrace_ops_get_func(ops); 840 func = ftrace_ops_get_func(ops);
@@ -840,6 +846,74 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
840 /* The update should never fail */ 846 /* The update should never fail */
841 WARN_ON(ret); 847 WARN_ON(ret);
842} 848}
849
850/* Return the address of the function the trampoline calls */
851static 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
869void 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 */
876static 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
904void *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
843#endif /* CONFIG_X86_64 */ 917#endif /* CONFIG_X86_64 */
844#endif /* CONFIG_DYNAMIC_FTRACE */ 918#endif /* CONFIG_DYNAMIC_FTRACE */
845 919
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 15f85eac7e95..422e1f8300b1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2952,6 +2952,22 @@ static void t_stop(struct seq_file *m, void *p)
2952 mutex_unlock(&ftrace_lock); 2952 mutex_unlock(&ftrace_lock);
2953} 2953}
2954 2954
2955void * __weak
2956arch_ftrace_trampoline_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
2957{
2958 return NULL;
2959}
2960
2961static void add_trampoline_func(struct seq_file *m, struct ftrace_ops *ops,
2962 struct dyn_ftrace *rec)
2963{
2964 void *ptr;
2965
2966 ptr = arch_ftrace_trampoline_func(ops, rec);
2967 if (ptr)
2968 seq_printf(m, " ->%pS", ptr);
2969}
2970
2955static int t_show(struct seq_file *m, void *v) 2971static int t_show(struct seq_file *m, void *v)
2956{ 2972{
2957 struct ftrace_iterator *iter = m->private; 2973 struct ftrace_iterator *iter = m->private;
@@ -2975,19 +2991,21 @@ static int t_show(struct seq_file *m, void *v)
2975 2991
2976 seq_printf(m, "%ps", (void *)rec->ip); 2992 seq_printf(m, "%ps", (void *)rec->ip);
2977 if (iter->flags & FTRACE_ITER_ENABLED) { 2993 if (iter->flags & FTRACE_ITER_ENABLED) {
2994 struct ftrace_ops *ops = NULL;
2995
2978 seq_printf(m, " (%ld)%s", 2996 seq_printf(m, " (%ld)%s",
2979 ftrace_rec_count(rec), 2997 ftrace_rec_count(rec),
2980 rec->flags & FTRACE_FL_REGS ? " R" : " "); 2998 rec->flags & FTRACE_FL_REGS ? " R" : " ");
2981 if (rec->flags & FTRACE_FL_TRAMP_EN) { 2999 if (rec->flags & FTRACE_FL_TRAMP_EN) {
2982 struct ftrace_ops *ops;
2983
2984 ops = ftrace_find_tramp_ops_any(rec); 3000 ops = ftrace_find_tramp_ops_any(rec);
2985 if (ops) 3001 if (ops)
2986 seq_printf(m, "\ttramp: %pS", 3002 seq_printf(m, "\ttramp: %pS",
2987 (void *)ops->trampoline); 3003 (void *)ops->trampoline);
2988 else 3004 else
2989 seq_printf(m, "\ttramp: ERROR!"); 3005 seq_printf(m, "\ttramp: ERROR!");
3006
2990 } 3007 }
3008 add_trampoline_func(m, ops, rec);
2991 } 3009 }
2992 3010
2993 seq_printf(m, "\n"); 3011 seq_printf(m, "\n");