1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 22521f2c2SPeter Oberparleiter /* 32521f2c2SPeter Oberparleiter * This code maintains a list of active profiling data structures. 42521f2c2SPeter Oberparleiter * 52521f2c2SPeter Oberparleiter * Copyright IBM Corp. 2009 62521f2c2SPeter Oberparleiter * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com> 72521f2c2SPeter Oberparleiter * 82521f2c2SPeter Oberparleiter * Uses gcc-internal data definitions. 92521f2c2SPeter Oberparleiter * Based on the gcov-kernel patch by: 102521f2c2SPeter Oberparleiter * Hubertus Franke <frankeh@us.ibm.com> 112521f2c2SPeter Oberparleiter * Nigel Hinds <nhinds@us.ibm.com> 122521f2c2SPeter Oberparleiter * Rajan Ravindran <rajancr@us.ibm.com> 132521f2c2SPeter Oberparleiter * Peter Oberparleiter <oberpar@linux.vnet.ibm.com> 142521f2c2SPeter Oberparleiter * Paul Larson 152521f2c2SPeter Oberparleiter */ 162521f2c2SPeter Oberparleiter 172521f2c2SPeter Oberparleiter #define pr_fmt(fmt) "gcov: " fmt 182521f2c2SPeter Oberparleiter 192521f2c2SPeter Oberparleiter #include <linux/init.h> 202521f2c2SPeter Oberparleiter #include <linux/module.h> 212521f2c2SPeter Oberparleiter #include <linux/mutex.h> 229d796e66SAndrey Ryabinin #include <linux/sched.h> 232521f2c2SPeter Oberparleiter #include "gcov.h" 242521f2c2SPeter Oberparleiter 25826eba0dSGreg Hackmann int gcov_events_enabled; 26826eba0dSGreg Hackmann DEFINE_MUTEX(gcov_lock); 2705384213SMartin Liska 282521f2c2SPeter Oberparleiter /** 292521f2c2SPeter Oberparleiter * gcov_enable_events - enable event reporting through gcov_event() 302521f2c2SPeter Oberparleiter * 312521f2c2SPeter Oberparleiter * Turn on reporting of profiling data load/unload-events through the 322521f2c2SPeter Oberparleiter * gcov_event() callback. Also replay all previous events once. This function 332521f2c2SPeter Oberparleiter * is needed because some events are potentially generated too early for the 342521f2c2SPeter Oberparleiter * callback implementation to handle them initially. 352521f2c2SPeter Oberparleiter */ 362521f2c2SPeter Oberparleiter void gcov_enable_events(void) 372521f2c2SPeter Oberparleiter { 388cbce376SFrantisek Hrbata struct gcov_info *info = NULL; 392521f2c2SPeter Oberparleiter 402521f2c2SPeter Oberparleiter mutex_lock(&gcov_lock); 412521f2c2SPeter Oberparleiter gcov_events_enabled = 1; 428cbce376SFrantisek Hrbata 432521f2c2SPeter Oberparleiter /* Perform event callback for previously registered entries. */ 449d796e66SAndrey Ryabinin while ((info = gcov_info_next(info))) { 452521f2c2SPeter Oberparleiter gcov_event(GCOV_ADD, info); 469d796e66SAndrey Ryabinin cond_resched(); 479d796e66SAndrey Ryabinin } 488cbce376SFrantisek Hrbata 492521f2c2SPeter Oberparleiter mutex_unlock(&gcov_lock); 502521f2c2SPeter Oberparleiter } 512521f2c2SPeter Oberparleiter 522521f2c2SPeter Oberparleiter #ifdef CONFIG_MODULES 532521f2c2SPeter Oberparleiter /* Update list and generate events when modules are unloaded. */ 542521f2c2SPeter Oberparleiter static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, 552521f2c2SPeter Oberparleiter void *data) 562521f2c2SPeter Oberparleiter { 572521f2c2SPeter Oberparleiter struct module *mod = data; 588cbce376SFrantisek Hrbata struct gcov_info *info = NULL; 598cbce376SFrantisek Hrbata struct gcov_info *prev = NULL; 602521f2c2SPeter Oberparleiter 612521f2c2SPeter Oberparleiter if (event != MODULE_STATE_GOING) 622521f2c2SPeter Oberparleiter return NOTIFY_OK; 632521f2c2SPeter Oberparleiter mutex_lock(&gcov_lock); 648cbce376SFrantisek Hrbata 652521f2c2SPeter Oberparleiter /* Remove entries located in module from linked list. */ 668cbce376SFrantisek Hrbata while ((info = gcov_info_next(info))) { 67c65abf35SRusty Russell if (within_module((unsigned long)info, mod)) { 688cbce376SFrantisek Hrbata gcov_info_unlink(prev, info); 692521f2c2SPeter Oberparleiter if (gcov_events_enabled) 702521f2c2SPeter Oberparleiter gcov_event(GCOV_REMOVE, info); 712521f2c2SPeter Oberparleiter } else 722521f2c2SPeter Oberparleiter prev = info; 732521f2c2SPeter Oberparleiter } 748cbce376SFrantisek Hrbata 752521f2c2SPeter Oberparleiter mutex_unlock(&gcov_lock); 762521f2c2SPeter Oberparleiter 772521f2c2SPeter Oberparleiter return NOTIFY_OK; 782521f2c2SPeter Oberparleiter } 792521f2c2SPeter Oberparleiter 802521f2c2SPeter Oberparleiter static struct notifier_block gcov_nb = { 812521f2c2SPeter Oberparleiter .notifier_call = gcov_module_notifier, 822521f2c2SPeter Oberparleiter }; 832521f2c2SPeter Oberparleiter 842521f2c2SPeter Oberparleiter static int __init gcov_init(void) 852521f2c2SPeter Oberparleiter { 862521f2c2SPeter Oberparleiter return register_module_notifier(&gcov_nb); 872521f2c2SPeter Oberparleiter } 882521f2c2SPeter Oberparleiter device_initcall(gcov_init); 892521f2c2SPeter Oberparleiter #endif /* CONFIG_MODULES */ 90