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 /** 53 * store_gcov_u32 - store 32 bit number in gcov format to buffer 54 * @buffer: target buffer or NULL 55 * @off: offset into the buffer 56 * @v: value to be stored 57 * 58 * Number format defined by gcc: numbers are recorded in the 32 bit 59 * unsigned binary form of the endianness of the machine generating the 60 * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't 61 * store anything. 62 */ 63 size_t store_gcov_u32(void *buffer, size_t off, u32 v) 64 { 65 u32 *data; 66 67 if (buffer) { 68 data = buffer + off; 69 *data = v; 70 } 71 72 return sizeof(*data); 73 } 74 75 /** 76 * store_gcov_u64 - store 64 bit number in gcov format to buffer 77 * @buffer: target buffer or NULL 78 * @off: offset into the buffer 79 * @v: value to be stored 80 * 81 * Number format defined by gcc: numbers are recorded in the 32 bit 82 * unsigned binary form of the endianness of the machine generating the 83 * file. 64 bit numbers are stored as two 32 bit numbers, the low part 84 * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store 85 * anything. 86 */ 87 size_t store_gcov_u64(void *buffer, size_t off, u64 v) 88 { 89 u32 *data; 90 91 if (buffer) { 92 data = buffer + off; 93 94 data[0] = (v & 0xffffffffUL); 95 data[1] = (v >> 32); 96 } 97 98 return sizeof(*data) * 2; 99 } 100 101 #ifdef CONFIG_MODULES 102 /* Update list and generate events when modules are unloaded. */ 103 static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, 104 void *data) 105 { 106 struct module *mod = data; 107 struct gcov_info *info = NULL; 108 struct gcov_info *prev = NULL; 109 110 if (event != MODULE_STATE_GOING) 111 return NOTIFY_OK; 112 mutex_lock(&gcov_lock); 113 114 /* Remove entries located in module from linked list. */ 115 while ((info = gcov_info_next(info))) { 116 if (gcov_info_within_module(info, mod)) { 117 gcov_info_unlink(prev, info); 118 if (gcov_events_enabled) 119 gcov_event(GCOV_REMOVE, info); 120 } else 121 prev = info; 122 } 123 124 mutex_unlock(&gcov_lock); 125 126 return NOTIFY_OK; 127 } 128 129 static struct notifier_block gcov_nb = { 130 .notifier_call = gcov_module_notifier, 131 }; 132 133 static int __init gcov_init(void) 134 { 135 return register_module_notifier(&gcov_nb); 136 } 137 device_initcall(gcov_init); 138 #endif /* CONFIG_MODULES */ 139