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