Branch data Line data Source code
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 : 3 : void gcov_enable_events(void) 37 : : { 38 : : struct gcov_info *info = NULL; 39 : : 40 : 3 : mutex_lock(&gcov_lock); 41 : 3 : gcov_events_enabled = 1; 42 : : 43 : : /* Perform event callback for previously registered entries. */ 44 : 3 : while ((info = gcov_info_next(info))) { 45 : 3 : gcov_event(GCOV_ADD, info); 46 : 3 : cond_resched(); 47 : : } 48 : : 49 : 3 : mutex_unlock(&gcov_lock); 50 : 3 : } 51 : : 52 : : #ifdef CONFIG_MODULES 53 : : /* Update list and generate events when modules are unloaded. */ 54 : 3 : 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 : 3 : if (event != MODULE_STATE_GOING) 62 : : return NOTIFY_OK; 63 : 0 : mutex_lock(&gcov_lock); 64 : : 65 : : /* Remove entries located in module from linked list. */ 66 : 0 : while ((info = gcov_info_next(info))) { 67 : 0 : if (gcov_info_within_module(info, mod)) { 68 : 0 : gcov_info_unlink(prev, info); 69 : 0 : if (gcov_events_enabled) 70 : 0 : gcov_event(GCOV_REMOVE, info); 71 : : } else 72 : : prev = info; 73 : : } 74 : : 75 : 0 : mutex_unlock(&gcov_lock); 76 : : 77 : 0 : return NOTIFY_OK; 78 : : } 79 : : 80 : : static struct notifier_block gcov_nb = { 81 : : .notifier_call = gcov_module_notifier, 82 : : }; 83 : : 84 : 3 : static int __init gcov_init(void) 85 : : { 86 : 3 : return register_module_notifier(&gcov_nb); 87 : : } 88 : : device_initcall(gcov_init); 89 : : #endif /* CONFIG_MODULES */