Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/gcov/base.c
29280 views
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 <[email protected]>
7
*
8
* Uses gcc-internal data definitions.
9
* Based on the gcov-kernel patch by:
10
* Hubertus Franke <[email protected]>
11
* Nigel Hinds <[email protected]>
12
* Rajan Ravindran <[email protected]>
13
* Peter Oberparleiter <[email protected]>
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
140