1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * This code maintains a list of active profiling data structures. 4 * 5 * Copyright IBM Corp. 2009 6 * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com> 7 * 8 * Uses gcc-internal data definitions. 9 * Based on the gcov-kernel patch by: 10 * Hubertus Franke <frankeh@us.ibm.com> 11 * Nigel Hinds <nhinds@us.ibm.com> 12 * Rajan Ravindran <rajancr@us.ibm.com> 13 * Peter Oberparleiter <oberpar@linux.vnet.ibm.com> 14 * Paul Larson 15 */ 16 17 #define pr_fmt(fmt) "gcov: " fmt 18 19 #include <linux/init.h> 20 #include <linux/module.h> 21 #include <linux/mutex.h> 22 #include <linux/sched.h> 23 #include "gcov.h" 24 25 static int gcov_events_enabled; 26 static DEFINE_MUTEX(gcov_lock); 27 28 /* 29 * __gcov_init is called by gcc-generated constructor code for each object 30 * file compiled with -fprofile-arcs. 31 */ 32 void __gcov_init(struct gcov_info *info) 33 { 34 static unsigned int gcov_version; 35 36 mutex_lock(&gcov_lock); 37 if (gcov_version == 0) { 38 gcov_version = gcov_info_version(info); 39 /* 40 * Printing gcc's version magic may prove useful for debugging 41 * incompatibility reports. 42 */ 43 pr_info("version magic: 0x%x\n", gcov_version); 44 } 45 /* 46 * Add new profiling data structure to list and inform event 47 * listener. 48 */ 49 gcov_info_link(info); 50 if (gcov_events_enabled) 51 gcov_event(GCOV_ADD, info); 52 mutex_unlock(&gcov_lock); 53 } 54 EXPORT_SYMBOL(__gcov_init); 55 56 /* 57 * These functions may be referenced by gcc-generated profiling code but serve 58 * no function for kernel profiling. 59 */ 60 void __gcov_flush(void) 61 { 62 /* Unused. */ 63 } 64 EXPORT_SYMBOL(__gcov_flush); 65 66 void __gcov_merge_add(gcov_type *counters, unsigned int n_counters) 67 { 68 /* Unused. */ 69 } 70 EXPORT_SYMBOL(__gcov_merge_add); 71 72 void __gcov_merge_single(gcov_type *counters, unsigned int n_counters) 73 { 74 /* Unused. */ 75 } 76 EXPORT_SYMBOL(__gcov_merge_single); 77 78 void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters) 79 { 80 /* Unused. */ 81 } 82 EXPORT_SYMBOL(__gcov_merge_delta); 83 84 void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters) 85 { 86 /* Unused. */ 87 } 88 EXPORT_SYMBOL(__gcov_merge_ior); 89 90 void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters) 91 { 92 /* Unused. */ 93 } 94 EXPORT_SYMBOL(__gcov_merge_time_profile); 95 96 void __gcov_merge_icall_topn(gcov_type *counters, unsigned int n_counters) 97 { 98 /* Unused. */ 99 } 100 EXPORT_SYMBOL(__gcov_merge_icall_topn); 101 102 void __gcov_exit(void) 103 { 104 /* Unused. */ 105 } 106 EXPORT_SYMBOL(__gcov_exit); 107 108 /** 109 * gcov_enable_events - enable event reporting through gcov_event() 110 * 111 * Turn on reporting of profiling data load/unload-events through the 112 * gcov_event() callback. Also replay all previous events once. This function 113 * is needed because some events are potentially generated too early for the 114 * callback implementation to handle them initially. 115 */ 116 void gcov_enable_events(void) 117 { 118 struct gcov_info *info = NULL; 119 120 mutex_lock(&gcov_lock); 121 gcov_events_enabled = 1; 122 123 /* Perform event callback for previously registered entries. */ 124 while ((info = gcov_info_next(info))) { 125 gcov_event(GCOV_ADD, info); 126 cond_resched(); 127 } 128 129 mutex_unlock(&gcov_lock); 130 } 131 132 #ifdef CONFIG_MODULES 133 /* Update list and generate events when modules are unloaded. */ 134 static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, 135 void *data) 136 { 137 struct module *mod = data; 138 struct gcov_info *info = NULL; 139 struct gcov_info *prev = NULL; 140 141 if (event != MODULE_STATE_GOING) 142 return NOTIFY_OK; 143 mutex_lock(&gcov_lock); 144 145 /* Remove entries located in module from linked list. */ 146 while ((info = gcov_info_next(info))) { 147 if (within_module((unsigned long)info, mod)) { 148 gcov_info_unlink(prev, info); 149 if (gcov_events_enabled) 150 gcov_event(GCOV_REMOVE, info); 151 } else 152 prev = info; 153 } 154 155 mutex_unlock(&gcov_lock); 156 157 return NOTIFY_OK; 158 } 159 160 static struct notifier_block gcov_nb = { 161 .notifier_call = gcov_module_notifier, 162 }; 163 164 static int __init gcov_init(void) 165 { 166 return register_module_notifier(&gcov_nb); 167 } 168 device_initcall(gcov_init); 169 #endif /* CONFIG_MODULES */ 170