Skip to content

Commit 15d5b02

Browse files
committed
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 <[email protected]> Tested-by: Masami Hiramatsu <[email protected]> Tested-by: Jiri Kosina <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent f3bea49 commit 15d5b02

File tree

2 files changed

+106
-14
lines changed

2 files changed

+106
-14
lines changed

arch/x86/kernel/ftrace.c

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ int ftrace_arch_code_modify_post_process(void)
4848
union 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+
800816
void 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

kernel/trace/ftrace.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,6 +2952,22 @@ static void t_stop(struct seq_file *m, void *p)
29522952
mutex_unlock(&ftrace_lock);
29532953
}
29542954

2955+
void * __weak
2956+
arch_ftrace_trampoline_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
2957+
{
2958+
return NULL;
2959+
}
2960+
2961+
static 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+
29552971
static int t_show(struct seq_file *m, void *v)
29562972
{
29572973
struct ftrace_iterator *iter = m->private;
@@ -2975,19 +2991,21 @@ static int t_show(struct seq_file *m, void *v)
29752991

29762992
seq_printf(m, "%ps", (void *)rec->ip);
29772993
if (iter->flags & FTRACE_ITER_ENABLED) {
2994+
struct ftrace_ops *ops = NULL;
2995+
29782996
seq_printf(m, " (%ld)%s",
29792997
ftrace_rec_count(rec),
29802998
rec->flags & FTRACE_FL_REGS ? " R" : " ");
29812999
if (rec->flags & FTRACE_FL_TRAMP_EN) {
2982-
struct ftrace_ops *ops;
2983-
29843000
ops = ftrace_find_tramp_ops_any(rec);
29853001
if (ops)
29863002
seq_printf(m, "\ttramp: %pS",
29873003
(void *)ops->trampoline);
29883004
else
29893005
seq_printf(m, "\ttramp: ERROR!");
3006+
29903007
}
3008+
add_trampoline_func(m, ops, rec);
29913009
}
29923010

29933011
seq_printf(m, "\n");

0 commit comments

Comments
 (0)