@@ -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