| @@ -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 | 2799 | static void ftrace_startup_enable(int command) |
| 2768 | 2800 | { |
| 2769 | 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 | 2966 | synchronize_rcu_tasks(); |
| 2935 | 2967 | |
| 2936 | 2968 | free_ops: |
| 2937 | | − arch_ftrace_trampoline_free(ops); |
| 2969 | + ftrace_trampoline_free(ops); |
| 2938 | 2970 | } |
| 2939 | 2971 | |
| 2940 | 2972 | return 0; |
| @@ -6178,6 +6210,27 @@ struct ftrace_mod_map { · 3237 unmodified lines |
| 6178 | 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 | 6234 | #ifdef CONFIG_MODULES |
| 6182 | 6235 | |
| 6183 | 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 | 6568 | struct ftrace_mod_map *mod_map; |
| 6516 | 6569 | struct ftrace_mod_func *mod_func; |
| 6570 | + int ret; |
| 6517 | 6571 | |
| 6518 | 6572 | preempt_disable(); |
| 6519 | 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 | 6594 | WARN_ON(1); |
| 6541 | 6595 | break; |
| 6542 | 6596 | } |
| 6597 | + ret = ftrace_get_trampoline_kallsym(symnum, value, type, name, |
| 6598 | + module_name, exported); |
| 6543 | 6599 | preempt_enable(); |
| 6544 | | − return -ERANGE; |
| 6600 | + return ret; |
| 6545 | 6601 | } |
| 6546 | 6602 | |
| 6547 | 6603 | #else |
| @@ -6553,6 +6609,18 @@ allocate_ftrace_mod_map(struct module *mod, · 5 unmodified lines |
| 6553 | 6609 | { |
| 6554 | 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 | 6624 | #endif /* CONFIG_MODULES */ |
| 6557 | 6625 | |
| 6558 | 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 | 6802 | static void ftrace_update_trampoline(struct ftrace_ops *ops) |
| 6735 | 6803 | { |
| 6804 | + unsigned long trampoline = ops->trampoline; |
| 6805 | + |
| 6736 | 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 | 6812 | void ftrace_init_trace_array(struct trace_array *tr) |