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 1 : void gcov_enable_events(void) 37 : { 38 1 : struct gcov_info *info = NULL; 39 : 40 1 : mutex_lock(&gcov_lock); 41 1 : gcov_events_enabled = 1; 42 : 43 : /* Perform event callback for previously registered entries. */ 44 956 : while ((info = gcov_info_next(info))) { 45 955 : gcov_event(GCOV_ADD, info); 46 955 : cond_resched(); 47 : } 48 : 49 1 : mutex_unlock(&gcov_lock); 50 1 : } 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 */