Symbols are needed for tools to describe instruction addresses. Pages allocated for ftrace's purposes need symbols to be created for them. Add such symbols to be visible via /proc/kallsyms. Example on x86 with CONFIG_DYNAMIC_FTRACE=y # echo function > /sys/kernel/debug/tracing/current_tracer # cat /proc/kallsyms | grep '\[__builtin__ftrace\]' ffffffffc0238000 t ftrace_trampoline [__builtin__ftrace] Note: This patch adds "__builtin__ftrace" as a module name in /proc/kallsyms for symbols for pages allocated for ftrace's purposes, even though "__builtin__ftrace" is not a module.
Showing the changes to kernel (2 of 3 files). Show all
Unified · Split
| @@ -482,6 +482,11 @@ static int get_ksymbol_mod(struct kallsym_iter *iter) · 481 unmodified lines | |||
| 482 | return 1; | 482 | return 1; |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | /* | ||
| 486 | * ftrace_mod_get_kallsym() may also get symbols for pages allocated for ftrace | ||
| 487 | * purposes. In that case "__builtin__ftrace" is used as a module name, even | ||
| 488 | * though "__builtin__ftrace" is not a module. | ||
| 489 | */ | ||
| 485 | static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter) | 490 | static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter) |
| 486 | { | 491 | { |
| 487 | int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end, | 492 | int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end, |
| @@ -2764,6 +2764,38 @@ void __weak arch_ftrace_trampoline_free(struct ftrace_ops *ops) · 2763 unmodified lines | |||
| 2764 | { | 2764 | { |
| 2765 | } | 2765 | } |
| 2766 | 2766 | ||
| 2767 | /* List of trace_ops that have allocated trampolines */ | ||
| 2768 | static LIST_HEAD(ftrace_ops_trampoline_list); | ||
| 2769 | |||
| 2770 | static void ftrace_add_trampoline_to_kallsyms(struct ftrace_ops *ops) | ||
| 2771 | { | ||
| 2772 | lockdep_assert_held(&ftrace_lock); | ||
| 2773 | list_add_rcu(&ops->list, &ftrace_ops_trampoline_list); | ||
| 2774 | } | ||
| 2775 | |||
| 2776 | static void ftrace_remove_trampoline_from_kallsyms(struct ftrace_ops *ops) | ||
| 2777 | { | ||
| 2778 | lockdep_assert_held(&ftrace_lock); | ||
| 2779 | list_del_rcu(&ops->list); | ||
| 2780 | } | ||
| 2781 | |||
| 2782 | /* | ||
| 2783 | * "__builtin__ftrace" is used as a module name in /proc/kallsyms for symbols | ||
| 2784 | * for pages allocated for ftrace purposes, even though "__builtin__ftrace" is | ||
| 2785 | * not a module. | ||
| 2786 | */ | ||
| 2787 | #define FTRACE_TRAMPOLINE_MOD "__builtin__ftrace" | ||
| 2788 | #define FTRACE_TRAMPOLINE_SYM "ftrace_trampoline" | ||
| 2789 | |||
| 2790 | static void ftrace_trampoline_free(struct ftrace_ops *ops) | ||
| 2791 | { | ||
| 2792 | if (ops && (ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP) && | ||
| 2793 | ops->trampoline) | ||
| 2794 | ftrace_remove_trampoline_from_kallsyms(ops); | ||
| 2795 | |||
| 2796 | arch_ftrace_trampoline_free(ops); | ||
| 2797 | } | ||
| 2798 | |||
| 2767 | static void ftrace_startup_enable(int command) | 2799 | static void ftrace_startup_enable(int command) |
| 2768 | { | 2800 | { |
| 2769 | if (saved_ftrace_func != ftrace_trace_function) { | 2801 | if (saved_ftrace_func != ftrace_trace_function) { |
| @@ -2934,7 +2966,7 @@ int ftrace_shutdown(struct ftrace_ops *ops, int command) · 164 unmodified lines | |||
| 2934 | synchronize_rcu_tasks(); | 2966 | synchronize_rcu_tasks(); |
| 2935 | 2967 | ||
| 2936 | free_ops: | 2968 | free_ops: |
| 2937 | arch_ftrace_trampoline_free(ops); | 2969 | ftrace_trampoline_free(ops); |
| 2938 | } | 2970 | } |
| 2939 | 2971 | ||
| 2940 | return 0; | 2972 | return 0; |
| @@ -6178,6 +6210,27 @@ struct ftrace_mod_map { · 3237 unmodified lines | |||
| 6178 | unsigned int num_funcs; | 6210 | unsigned int num_funcs; |
| 6179 | }; | 6211 | }; |
| 6180 | 6212 | ||
| 6213 | static int ftrace_get_trampoline_kallsym(unsigned int symnum, | ||
| 6214 | unsigned long *value, char *type, | ||
| 6215 | char *name, char *module_name, | ||
| 6216 | int *exported) | ||
| 6217 | { | ||
| 6218 | struct ftrace_ops *op; | ||
| 6219 | |||
| 6220 | list_for_each_entry_rcu(op, &ftrace_ops_trampoline_list, list) { | ||
| 6221 | if (!op->trampoline || symnum--) | ||
| 6222 | continue; | ||
| 6223 | *value = op->trampoline; | ||
| 6224 | *type = 't'; | ||
| 6225 | strlcpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN); | ||
| 6226 | strlcpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN); | ||
| 6227 | *exported = 0; | ||
| 6228 | return 0; | ||
| 6229 | } | ||
| 6230 | |||
| 6231 | return -ERANGE; | ||
| 6232 | } | ||
| 6233 | |||
| 6181 | #ifdef CONFIG_MODULES | 6234 | #ifdef CONFIG_MODULES |
| 6182 | 6235 | ||
| 6183 | #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next) | 6236 | #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next) |
| @@ -6514,6 +6567,7 @@ int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value, · 330 unmodified lines | |||
| 6514 | { | 6567 | { |
| 6515 | struct ftrace_mod_map *mod_map; | 6568 | struct ftrace_mod_map *mod_map; |
| 6516 | struct ftrace_mod_func *mod_func; | 6569 | struct ftrace_mod_func *mod_func; |
| 6570 | int ret; | ||
| 6517 | 6571 | ||
| 6518 | preempt_disable(); | 6572 | preempt_disable(); |
| 6519 | list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) { | 6573 | list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) { |
| @@ -6540,8 +6594,10 @@ int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value, · 20 unmodified lines | |||
| 6540 | WARN_ON(1); | 6594 | WARN_ON(1); |
| 6541 | break; | 6595 | break; |
| 6542 | } | 6596 | } |
| 6597 | ret = ftrace_get_trampoline_kallsym(symnum, value, type, name, | ||
| 6598 | module_name, exported); | ||
| 6543 | preempt_enable(); | 6599 | preempt_enable(); |
| 6544 | return -ERANGE; | 6600 | return ret; |
| 6545 | } | 6601 | } |
| 6546 | 6602 | ||
| 6547 | #else | 6603 | #else |
| @@ -6553,6 +6609,18 @@ allocate_ftrace_mod_map(struct module *mod, · 5 unmodified lines | |||
| 6553 | { | 6609 | { |
| 6554 | return NULL; | 6610 | return NULL; |
| 6555 | } | 6611 | } |
| 6612 | int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value, | ||
| 6613 | char *type, char *name, char *module_name, | ||
| 6614 | int *exported) | ||
| 6615 | { | ||
| 6616 | int ret; | ||
| 6617 | |||
| 6618 | preempt_disable(); | ||
| 6619 | ret = ftrace_get_trampoline_kallsym(symnum, value, type, name, | ||
| 6620 | module_name, exported); | ||
| 6621 | preempt_enable(); | ||
| 6622 | return ret; | ||
| 6623 | } | ||
| 6556 | #endif /* CONFIG_MODULES */ | 6624 | #endif /* CONFIG_MODULES */ |
| 6557 | 6625 | ||
| 6558 | struct ftrace_init_func { | 6626 | struct ftrace_init_func { |
| @@ -6733,7 +6801,12 @@ void __weak arch_ftrace_update_trampoline(struct ftrace_ops *ops) · 174 unmodified lines | |||
| 6733 | 6801 | ||
| 6734 | static void ftrace_update_trampoline(struct ftrace_ops *ops) | 6802 | static void ftrace_update_trampoline(struct ftrace_ops *ops) |
| 6735 | { | 6803 | { |
| 6804 | unsigned long trampoline = ops->trampoline; | ||
| 6805 | |||
| 6736 | arch_ftrace_update_trampoline(ops); | 6806 | arch_ftrace_update_trampoline(ops); |
| 6807 | if (ops->trampoline && ops->trampoline != trampoline && | ||
| 6808 | (ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP)) | ||
| 6809 | ftrace_add_trampoline_to_kallsyms(ops); | ||
| 6737 | } | 6810 | } |
| 6738 | 6811 | ||
| 6739 | void ftrace_init_trace_array(struct trace_array *tr) | 6812 | void ftrace_init_trace_array(struct trace_array *tr) |