base.c (3478B)
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 25int gcov_events_enabled; 26DEFINE_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 */ 36void 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 */ 63size_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 */ 87size_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. */ 103static 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 129static struct notifier_block gcov_nb = { 130 .notifier_call = gcov_module_notifier, 131}; 132 133static int __init gcov_init(void) 134{ 135 return register_module_notifier(&gcov_nb); 136} 137device_initcall(gcov_init); 138#endif /* CONFIG_MODULES */