@@ -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
59266068void __init ftrace_init (void )
0 commit comments