@@ -5675,6 +5675,21 @@ static int ftrace_process_locs(struct module *mod,
5675
5675
return ret ;
5676
5676
}
5677
5677
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
+
5678
5693
#ifdef CONFIG_MODULES
5679
5694
5680
5695
#define next_to_ftrace_page (p ) container_of(p, struct ftrace_page, next)
@@ -5868,23 +5883,146 @@ void ftrace_module_init(struct module *mod)
5868
5883
ftrace_process_locs (mod , mod -> ftrace_callsites ,
5869
5884
mod -> ftrace_callsites + mod -> num_ftrace_callsites );
5870
5885
}
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
+ }
5871
6000
#endif /* CONFIG_MODULES */
5872
6001
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 )
5874
6003
{
5875
6004
unsigned long start = (unsigned long )(start_ptr );
5876
6005
unsigned long end = (unsigned long )(end_ptr );
5877
6006
struct ftrace_page * * last_pg = & ftrace_pages_start ;
5878
6007
struct ftrace_page * pg ;
5879
6008
struct dyn_ftrace * rec ;
5880
6009
struct dyn_ftrace key ;
6010
+ struct ftrace_mod_map * mod_map = NULL ;
5881
6011
int order ;
5882
6012
5883
6013
key .ip = start ;
5884
6014
key .flags = end ; /* overload flags, as it is unsigned long */
5885
6015
5886
6016
mutex_lock (& ftrace_lock );
5887
6017
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
+
5888
6026
for (pg = ftrace_pages_start ; pg ; last_pg = & pg -> next , pg = * last_pg ) {
5889
6027
if (end < pg -> records [0 ].ip ||
5890
6028
start >= (pg -> records [pg -> index - 1 ].ip + MCOUNT_INSN_SIZE ))
@@ -5895,6 +6033,10 @@ void ftrace_free_mem(void *start_ptr, void *end_ptr)
5895
6033
ftrace_cmp_recs );
5896
6034
if (!rec )
5897
6035
continue ;
6036
+
6037
+ if (mod_map )
6038
+ save_ftrace_mod_rec (mod_map , rec );
6039
+
5898
6040
pg -> index -- ;
5899
6041
ftrace_update_tot_cnt -- ;
5900
6042
if (!pg -> index ) {
@@ -5920,7 +6062,7 @@ void __init ftrace_free_init_mem(void)
5920
6062
void * start = (void * )(& __init_begin );
5921
6063
void * end = (void * )(& __init_end );
5922
6064
5923
- ftrace_free_mem (start , end );
6065
+ ftrace_free_mem (NULL , start , end );
5924
6066
}
5925
6067
5926
6068
void __init ftrace_init (void )
0 commit comments