Skip to content

Commit

Permalink
ftrace/kallsyms: Have /proc/kallsyms show saved mod init functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steven Rostedt (VMware) committed Oct 6, 2017
1 parent 6aa6978 commit 6171a03
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 6 deletions.
9 changes: 9 additions & 0 deletions include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,22 @@ 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,
unsigned long *off, char **modname, char *sym)
{
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


Expand Down
38 changes: 32 additions & 6 deletions kernel/kallsyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
40 changes: 40 additions & 0 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);

Expand Down Expand Up @@ -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) { }
Expand Down

0 comments on commit 6171a03

Please sign in to comment.