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 int gcov_events_enabled; 26 DEFINE_MUTEX(gcov_lock); 27 28 /** 29 * gcov_enable_events - enable event reporting through gcov_event() 30 * 31 * Turn on reporting of profiling data load/unload-events through the 32 * gcov_event() callback. Also replay all previous events once. This function 33 * is needed because some events are potentially generated too early for the 34 * callback implementation to handle them initially. 35 */ 36 void gcov_enable_events(void) 37 { 38 struct gcov_info *info = NULL; 39 40 mutex_lock(&gcov_lock); 41 gcov_events_enabled = 1; 42 43 /* Perform event callback for previously registered entries. */ 44 while ((info = gcov_info_next(info))) { 45 gcov_event(GCOV_ADD, info); 46 cond_resched(); 47 } 48 49 mutex_unlock(&gcov_lock); 50 } 51 52 #ifdef CONFIG_MODULES 53 /* Update list and generate events when modules are unloaded. */ 54 static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, 55 void *data) 56 { 57 struct module *mod = data; 58 struct gcov_info *info = NULL; 59 struct gcov_info *prev = NULL; 60 61 if (event != MODULE_STATE_GOING) 62 return NOTIFY_OK; 63 mutex_lock(&gcov_lock); 64 65 /* Remove entries located in module from linked list. */ 66 while ((info = gcov_info_next(info))) { 67 if (gcov_info_within_module(info, mod)) { 68 gcov_info_unlink(prev, info); 69 if (gcov_events_enabled) 70 gcov_event(GCOV_REMOVE, info); 71 } else 72 prev = info; 73 } 74 75 mutex_unlock(&gcov_lock); 76 77 return NOTIFY_OK; 78 } 79 80 static struct notifier_block gcov_nb = { 81 .notifier_call = gcov_module_notifier, 82 }; 83 84 static int __init gcov_init(void) 85 { 86 return register_module_notifier(&gcov_nb); 87 } 88 device_initcall(gcov_init); 89 #endif /* CONFIG_MODULES */ 90