Skip to content

Commit aba4b5c

Browse files
committed
ftrace: Save module init functions kallsyms symbols for tracing
If function tracing is active when the module init functions are freed, then store them to be referenced by kallsyms. As module init functions can now be traced on module load, they were useless: ># echo ':mod:snd_seq' > set_ftrace_filter ># echo function > current_tracer ># modprobe snd_seq ># cat trace # tracer: function # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | modprobe-2786 [000] .... 3189.037874: 0xffffffffa0860000 <-do_one_initcall modprobe-2786 [000] .... 3189.037876: 0xffffffffa086004d <-0xffffffffa086000f modprobe-2786 [000] .... 3189.037876: 0xffffffffa086010d <-0xffffffffa0860018 modprobe-2786 [000] .... 3189.037877: 0xffffffffa086011a <-0xffffffffa0860021 modprobe-2786 [000] .... 3189.037877: 0xffffffffa0860080 <-0xffffffffa086002a modprobe-2786 [000] .... 3189.039523: 0xffffffffa0860400 <-0xffffffffa0860033 modprobe-2786 [000] .... 3189.039523: 0xffffffffa086038a <-0xffffffffa086041c modprobe-2786 [000] .... 3189.039591: 0xffffffffa086038a <-0xffffffffa0860436 modprobe-2786 [000] .... 3189.039657: 0xffffffffa086038a <-0xffffffffa0860450 modprobe-2786 [000] .... 3189.039719: 0xffffffffa0860127 <-0xffffffffa086003c modprobe-2786 [000] .... 3189.039742: snd_seq_create_kernel_client <-0xffffffffa08601f6 When the output is shown, the kallsyms for the module init functions have already been freed, and the output of the trace can not convert them to their function names. Now this looks like this: # tracer: function # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | modprobe-2463 [002] .... 174.243237: alsa_seq_init <-do_one_initcall modprobe-2463 [002] .... 174.243239: client_init_data <-alsa_seq_init modprobe-2463 [002] .... 174.243240: snd_sequencer_memory_init <-alsa_seq_init modprobe-2463 [002] .... 174.243240: snd_seq_queues_init <-alsa_seq_init modprobe-2463 [002] .... 174.243240: snd_sequencer_device_init <-alsa_seq_init modprobe-2463 [002] .... 174.244860: snd_seq_info_init <-alsa_seq_init modprobe-2463 [002] .... 174.244861: create_info_entry <-snd_seq_info_init modprobe-2463 [002] .... 174.244936: create_info_entry <-snd_seq_info_init modprobe-2463 [002] .... 174.245003: create_info_entry <-snd_seq_info_init modprobe-2463 [002] .... 174.245072: snd_seq_system_client_init <-alsa_seq_init modprobe-2463 [002] .... 174.245094: snd_seq_create_kernel_client <-snd_seq_system_client_init Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 3e23428 commit aba4b5c

File tree

4 files changed

+168
-5
lines changed

4 files changed

+168
-5
lines changed

include/linux/ftrace.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ static inline void early_trace_init(void) { }
5151
struct module;
5252
struct ftrace_hash;
5353

54+
#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
55+
defined(CONFIG_DYNAMIC_FTRACE)
56+
const char *
57+
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
58+
unsigned long *off, char **modname, char *sym);
59+
#else
60+
static inline const char *
61+
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
62+
unsigned long *off, char **modname, char *sym)
63+
{
64+
return NULL;
65+
}
66+
#endif
67+
68+
5469
#ifdef CONFIG_FUNCTION_TRACER
5570

5671
extern int ftrace_enabled;
@@ -151,10 +166,10 @@ struct ftrace_ops_hash {
151166
};
152167

153168
void ftrace_free_init_mem(void);
154-
void ftrace_free_mem(void *start, void *end);
169+
void ftrace_free_mem(struct module *mod, void *start, void *end);
155170
#else
156171
static inline void ftrace_free_init_mem(void) { }
157-
static inline void ftrace_free_mem(void *start, void *end) { }
172+
static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { }
158173
#endif
159174

160175
/*
@@ -272,6 +287,7 @@ static inline int ftrace_nr_registered_ops(void)
272287
static inline void clear_ftrace_function(void) { }
273288
static inline void ftrace_kill(void) { }
274289
static inline void ftrace_free_init_mem(void) { }
290+
static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { }
275291
#endif /* CONFIG_FUNCTION_TRACER */
276292

277293
#ifdef CONFIG_STACK_TRACER

kernel/kallsyms.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/ctype.h>
2525
#include <linux/slab.h>
2626
#include <linux/filter.h>
27+
#include <linux/ftrace.h>
2728
#include <linux/compiler.h>
2829

2930
#include <asm/sections.h>
@@ -337,6 +338,10 @@ const char *kallsyms_lookup(unsigned long addr,
337338
if (!ret)
338339
ret = bpf_address_lookup(addr, symbolsize,
339340
offset, modname, namebuf);
341+
342+
if (!ret)
343+
ret = ftrace_mod_address_lookup(addr, symbolsize,
344+
offset, modname, namebuf);
340345
return ret;
341346
}
342347

kernel/module.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3473,7 +3473,7 @@ static noinline int do_init_module(struct module *mod)
34733473
if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
34743474
async_synchronize_full();
34753475

3476-
ftrace_free_mem(mod->init_layout.base, mod->init_layout.base +
3476+
ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
34773477
mod->init_layout.size);
34783478
mutex_lock(&module_mutex);
34793479
/* Drop initial reference. */

kernel/trace/ftrace.c

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5675,6 +5675,21 @@ static int ftrace_process_locs(struct module *mod,
56755675
return ret;
56765676
}
56775677

5678+
struct ftrace_mod_func {
5679+
struct list_head list;
5680+
char *name;
5681+
unsigned long ip;
5682+
unsigned int size;
5683+
};
5684+
5685+
struct ftrace_mod_map {
5686+
struct list_head list;
5687+
struct module *mod;
5688+
unsigned long start_addr;
5689+
unsigned long end_addr;
5690+
struct list_head funcs;
5691+
};
5692+
56785693
#ifdef CONFIG_MODULES
56795694

56805695
#define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
@@ -5868,23 +5883,146 @@ void ftrace_module_init(struct module *mod)
58685883
ftrace_process_locs(mod, mod->ftrace_callsites,
58695884
mod->ftrace_callsites + mod->num_ftrace_callsites);
58705885
}
5886+
5887+
static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
5888+
struct dyn_ftrace *rec)
5889+
{
5890+
struct ftrace_mod_func *mod_func;
5891+
unsigned long symsize;
5892+
unsigned long offset;
5893+
char str[KSYM_SYMBOL_LEN];
5894+
char *modname;
5895+
const char *ret;
5896+
5897+
ret = kallsyms_lookup(rec->ip, &symsize, &offset, &modname, str);
5898+
if (!ret)
5899+
return;
5900+
5901+
mod_func = kmalloc(sizeof(*mod_func), GFP_KERNEL);
5902+
if (!mod_func)
5903+
return;
5904+
5905+
mod_func->name = kstrdup(str, GFP_KERNEL);
5906+
if (!mod_func->name) {
5907+
kfree(mod_func);
5908+
return;
5909+
}
5910+
5911+
mod_func->ip = rec->ip - offset;
5912+
mod_func->size = symsize;
5913+
5914+
list_add_rcu(&mod_func->list, &mod_map->funcs);
5915+
}
5916+
5917+
static LIST_HEAD(ftrace_mod_maps);
5918+
5919+
static struct ftrace_mod_map *
5920+
allocate_ftrace_mod_map(struct module *mod,
5921+
unsigned long start, unsigned long end)
5922+
{
5923+
struct ftrace_mod_map *mod_map;
5924+
5925+
mod_map = kmalloc(sizeof(*mod_map), GFP_KERNEL);
5926+
if (!mod_map)
5927+
return NULL;
5928+
5929+
mod_map->mod = mod;
5930+
mod_map->start_addr = start;
5931+
mod_map->end_addr = end;
5932+
5933+
INIT_LIST_HEAD_RCU(&mod_map->funcs);
5934+
5935+
list_add_rcu(&mod_map->list, &ftrace_mod_maps);
5936+
5937+
return mod_map;
5938+
}
5939+
5940+
static const char *
5941+
ftrace_func_address_lookup(struct ftrace_mod_map *mod_map,
5942+
unsigned long addr, unsigned long *size,
5943+
unsigned long *off, char *sym)
5944+
{
5945+
struct ftrace_mod_func *found_func = NULL;
5946+
struct ftrace_mod_func *mod_func;
5947+
5948+
list_for_each_entry_rcu(mod_func, &mod_map->funcs, list) {
5949+
if (addr >= mod_func->ip &&
5950+
addr < mod_func->ip + mod_func->size) {
5951+
found_func = mod_func;
5952+
break;
5953+
}
5954+
}
5955+
5956+
if (found_func) {
5957+
if (size)
5958+
*size = found_func->size;
5959+
if (off)
5960+
*off = addr - found_func->ip;
5961+
if (sym)
5962+
strlcpy(sym, found_func->name, KSYM_NAME_LEN);
5963+
5964+
return found_func->name;
5965+
}
5966+
5967+
return NULL;
5968+
}
5969+
5970+
const char *
5971+
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
5972+
unsigned long *off, char **modname, char *sym)
5973+
{
5974+
struct ftrace_mod_map *mod_map;
5975+
const char *ret = NULL;
5976+
5977+
preempt_disable();
5978+
list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) {
5979+
ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym);
5980+
if (ret) {
5981+
if (modname)
5982+
*modname = mod_map->mod->name;
5983+
break;
5984+
}
5985+
}
5986+
preempt_enable();
5987+
5988+
return ret;
5989+
}
5990+
5991+
#else
5992+
static void save_ftrace_mod_rec(struct ftrace_mod_map *mod_map,
5993+
struct dyn_ftrace *rec) { }
5994+
static inline struct ftrace_mod_map *
5995+
allocate_ftrace_mod_map(struct module *mod,
5996+
unsigned long start, unsigned long end)
5997+
{
5998+
return NULL;
5999+
}
58716000
#endif /* CONFIG_MODULES */
58726001

5873-
void ftrace_free_mem(void *start_ptr, void *end_ptr)
6002+
void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
58746003
{
58756004
unsigned long start = (unsigned long)(start_ptr);
58766005
unsigned long end = (unsigned long)(end_ptr);
58776006
struct ftrace_page **last_pg = &ftrace_pages_start;
58786007
struct ftrace_page *pg;
58796008
struct dyn_ftrace *rec;
58806009
struct dyn_ftrace key;
6010+
struct ftrace_mod_map *mod_map = NULL;
58816011
int order;
58826012

58836013
key.ip = start;
58846014
key.flags = end; /* overload flags, as it is unsigned long */
58856015

58866016
mutex_lock(&ftrace_lock);
58876017

6018+
/*
6019+
* If we are freeing module init memory, then check if
6020+
* any tracer is active. If so, we need to save a mapping of
6021+
* the module functions being freed with the address.
6022+
*/
6023+
if (mod && ftrace_ops_list != &ftrace_list_end)
6024+
mod_map = allocate_ftrace_mod_map(mod, start, end);
6025+
58886026
for (pg = ftrace_pages_start; pg; last_pg = &pg->next, pg = *last_pg) {
58896027
if (end < pg->records[0].ip ||
58906028
start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
@@ -5895,6 +6033,10 @@ void ftrace_free_mem(void *start_ptr, void *end_ptr)
58956033
ftrace_cmp_recs);
58966034
if (!rec)
58976035
continue;
6036+
6037+
if (mod_map)
6038+
save_ftrace_mod_rec(mod_map, rec);
6039+
58986040
pg->index--;
58996041
ftrace_update_tot_cnt--;
59006042
if (!pg->index) {
@@ -5920,7 +6062,7 @@ void __init ftrace_free_init_mem(void)
59206062
void *start = (void *)(&__init_begin);
59216063
void *end = (void *)(&__init_end);
59226064

5923-
ftrace_free_mem(start, end);
6065+
ftrace_free_mem(NULL, start, end);
59246066
}
59256067

59266068
void __init ftrace_init(void)

0 commit comments

Comments
 (0)