Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139// SPDX-License-Identifier: GPL-2.0/* * This code maintains a list of active profiling data structures. * * Copyright IBM Corp. 2009 * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com> * * Uses gcc-internal data definitions. * Based on the gcov-kernel patch by: * Hubertus Franke <frankeh@us.ibm.com> * Nigel Hinds <nhinds@us.ibm.com> * Rajan Ravindran <rajancr@us.ibm.com> * Peter Oberparleiter <oberpar@linux.vnet.ibm.com> * Paul Larson */
#define pr_fmt(fmt) "gcov: " fmt
#include <linux/init.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/sched.h>#include "gcov.h"
int gcov_events_enabled;DEFINE_MUTEX(gcov_lock);
/** * gcov_enable_events - enable event reporting through gcov_event() * * Turn on reporting of profiling data load/unload-events through the * gcov_event() callback. Also replay all previous events once. This function * is needed because some events are potentially generated too early for the * callback implementation to handle them initially. */void gcov_enable_events(void){ struct gcov_info *info = NULL;
mutex_lock(&gcov_lock); gcov_events_enabled = 1;
/* Perform event callback for previously registered entries. */ while ((info = gcov_info_next(info))) { gcov_event(GCOV_ADD, info); cond_resched(); }
mutex_unlock(&gcov_lock);}
/** * store_gcov_u32 - store 32 bit number in gcov format to buffer * @buffer: target buffer or NULL * @off: offset into the buffer * @v: value to be stored * * Number format defined by gcc: numbers are recorded in the 32 bit * unsigned binary form of the endianness of the machine generating the * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't * store anything. */size_t store_gcov_u32(void *buffer, size_t off, u32 v){ u32 *data;
if (buffer) { data = buffer + off; *data = v; }
return sizeof(*data);}
/** * store_gcov_u64 - store 64 bit number in gcov format to buffer * @buffer: target buffer or NULL * @off: offset into the buffer * @v: value to be stored * * Number format defined by gcc: numbers are recorded in the 32 bit * unsigned binary form of the endianness of the machine generating the * file. 64 bit numbers are stored as two 32 bit numbers, the low part * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store * anything. */size_t store_gcov_u64(void *buffer, size_t off, u64 v){ u32 *data;
if (buffer) { data = buffer + off;
data[0] = (v & 0xffffffffUL); data[1] = (v >> 32); }
return sizeof(*data) * 2;}
#ifdef CONFIG_MODULES/* Update list and generate events when modules are unloaded. */static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, void *data){ struct module *mod = data; struct gcov_info *info = NULL; struct gcov_info *prev = NULL;
if (event != MODULE_STATE_GOING) return NOTIFY_OK; mutex_lock(&gcov_lock);
/* Remove entries located in module from linked list. */ while ((info = gcov_info_next(info))) { if (gcov_info_within_module(info, mod)) { gcov_info_unlink(prev, info); if (gcov_events_enabled) gcov_event(GCOV_REMOVE, info); } else prev = info; }
mutex_unlock(&gcov_lock);
return NOTIFY_OK;}
static struct notifier_block gcov_nb = { .notifier_call = gcov_module_notifier,};
static int __init gcov_init(void){ return register_module_notifier(&gcov_nb);}device_initcall(gcov_init);#endif /* CONFIG_MODULES */