]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions
authorSteven Rostedt (VMware) <rostedt@goodmis.org>
Wed, 6 Sep 2017 12:40:41 +0000 (08:40 -0400)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Fri, 6 Oct 2017 03:10:42 +0000 (23:10 -0400)
If a module is loaded while tracing is enabled, then there's a possibility
that the module init functions were traced. These functions have their name
and address stored by ftrace such that it can translate the function address
that is written into the buffer into a human readable function name.

As userspace tools may be doing the same, they need a way to map function
names to their address as well. This is done through reading /proc/kallsyms.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
include/linux/ftrace.h
kernel/kallsyms.c
kernel/trace/ftrace.c

index 202b40784c4e816ea341925d361e279e60b205c3..346f8294e40a118f6bedd6ef957deca6dc1d3ee9 100644 (file)
@@ -56,6 +56,9 @@ struct ftrace_hash;
 const char *
 ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
                   unsigned long *off, char **modname, char *sym);
+int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+                          char *type, char *name,
+                          char *module_name, int *exported);
 #else
 static inline const char *
 ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
@@ -63,6 +66,12 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
 {
        return NULL;
 }
+static inline int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+                                        char *type, char *name,
+                                        char *module_name, int *exported)
+{
+       return -1;
+}
 #endif
 
 
index 976ecb9275d9971413644d25e5f631b8eb3ae86a..1966fe1c2b57fe7924a34200154f47a7911c562c 100644 (file)
@@ -479,6 +479,7 @@ EXPORT_SYMBOL(__print_symbol);
 struct kallsym_iter {
        loff_t pos;
        loff_t pos_mod_end;
+       loff_t pos_ftrace_mod_end;
        unsigned long value;
        unsigned int nameoff; /* If iterating in core kernel symbols. */
        char type;
@@ -501,11 +502,25 @@ static int get_ksymbol_mod(struct kallsym_iter *iter)
        return 1;
 }
 
+static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter)
+{
+       int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end,
+                                        &iter->value, &iter->type,
+                                        iter->name, iter->module_name,
+                                        &iter->exported);
+       if (ret < 0) {
+               iter->pos_ftrace_mod_end = iter->pos;
+               return 0;
+       }
+
+       return 1;
+}
+
 static int get_ksymbol_bpf(struct kallsym_iter *iter)
 {
        iter->module_name[0] = '\0';
        iter->exported = 0;
-       return bpf_get_kallsym(iter->pos - iter->pos_mod_end,
+       return bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
                               &iter->value, &iter->type,
                               iter->name) < 0 ? 0 : 1;
 }
@@ -530,20 +545,31 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
        iter->name[0] = '\0';
        iter->nameoff = get_symbol_offset(new_pos);
        iter->pos = new_pos;
-       if (new_pos == 0)
+       if (new_pos == 0) {
                iter->pos_mod_end = 0;
+               iter->pos_ftrace_mod_end = 0;
+       }
 }
 
 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
 {
        iter->pos = pos;
 
-       if (iter->pos_mod_end > 0 &&
-           iter->pos_mod_end < iter->pos)
+       if (iter->pos_ftrace_mod_end > 0 &&
+           iter->pos_ftrace_mod_end < iter->pos)
                return get_ksymbol_bpf(iter);
 
-       if (!get_ksymbol_mod(iter))
-               return get_ksymbol_bpf(iter);
+       if (iter->pos_mod_end > 0 &&
+           iter->pos_mod_end < iter->pos) {
+               if (!get_ksymbol_ftrace_mod(iter))
+                       return get_ksymbol_bpf(iter);
+               return 1;
+       }
+
+       if (!get_ksymbol_mod(iter)) {
+               if (!get_ksymbol_ftrace_mod(iter))
+                       return get_ksymbol_bpf(iter);
+       }
 
        return 1;
 }
index a5824408bed997133fc931e0e325ee5fb33cb37f..9e99bd55732e14b6ac5bf4f80e1b95cf858f6de1 100644 (file)
@@ -5689,6 +5689,7 @@ struct ftrace_mod_map {
        unsigned long           start_addr;
        unsigned long           end_addr;
        struct list_head        funcs;
+       unsigned int            num_funcs;
 };
 
 #ifdef CONFIG_MODULES
@@ -5940,6 +5941,8 @@ static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
        mod_func->ip = rec->ip - offset;
        mod_func->size = symsize;
 
+       mod_map->num_funcs++;
+
        list_add_rcu(&mod_func->list, &mod_map->funcs);
 }
 
@@ -5956,6 +5959,7 @@ allocate_ftrace_mod_map(struct module *mod,
        mod_map->mod = mod;
        mod_map->start_addr = start;
        mod_map->end_addr = end;
+       mod_map->num_funcs = 0;
 
        INIT_LIST_HEAD_RCU(&mod_map->funcs);
 
@@ -6016,6 +6020,42 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
        return ret;
 }
 
+int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,
+                          char *type, char *name,
+                          char *module_name, int *exported)
+{
+       struct ftrace_mod_map *mod_map;
+       struct ftrace_mod_func *mod_func;
+
+       preempt_disable();
+       list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
+
+               if (symnum >= mod_map->num_funcs) {
+                       symnum -= mod_map->num_funcs;
+                       continue;
+               }
+
+               list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
+                       if (symnum > 1) {
+                               symnum--;
+                               continue;
+                       }
+
+                       *value = mod_func->ip;
+                       *type = 'T';
+                       strlcpy(name, mod_func->name, KSYM_NAME_LEN);
+                       strlcpy(module_name, mod_map->mod->name, MODULE_NAME_LEN);
+                       *exported = 1;
+                       preempt_enable();
+                       return 0;
+               }
+               WARN_ON(1);
+               break;
+       }
+       preempt_enable();
+       return -ERANGE;
+}
+
 #else
 static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
                                struct dyn_ftrace *rec) { }