Blame view

kernel/gcov/base.c 3.6 KB
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *  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 "gcov.h"
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
22
23
24
25
26
27
28
29
30
31
32
33
34
  static int gcov_events_enabled;
  static DEFINE_MUTEX(gcov_lock);
  
  /*
   * __gcov_init is called by gcc-generated constructor code for each object
   * file compiled with -fprofile-arcs.
   */
  void __gcov_init(struct gcov_info *info)
  {
  	static unsigned int gcov_version;
  
  	mutex_lock(&gcov_lock);
  	if (gcov_version == 0) {
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
35
  		gcov_version = gcov_info_version(info);
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
36
37
38
39
40
41
42
43
44
45
46
  		/*
  		 * Printing gcc's version magic may prove useful for debugging
  		 * incompatibility reports.
  		 */
  		pr_info("version magic: 0x%x
  ", gcov_version);
  	}
  	/*
  	 * Add new profiling data structure to list and inform event
  	 * listener.
  	 */
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
47
  	gcov_info_link(info);
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  	if (gcov_events_enabled)
  		gcov_event(GCOV_ADD, info);
  	mutex_unlock(&gcov_lock);
  }
  EXPORT_SYMBOL(__gcov_init);
  
  /*
   * These functions may be referenced by gcc-generated profiling code but serve
   * no function for kernel profiling.
   */
  void __gcov_flush(void)
  {
  	/* Unused. */
  }
  EXPORT_SYMBOL(__gcov_flush);
  
  void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
  {
  	/* Unused. */
  }
  EXPORT_SYMBOL(__gcov_merge_add);
  
  void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
  {
  	/* Unused. */
  }
  EXPORT_SYMBOL(__gcov_merge_single);
  
  void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
  {
  	/* Unused. */
  }
  EXPORT_SYMBOL(__gcov_merge_delta);
5f41ea038   Frantisek Hrbata   gcov: add support...
81
82
83
84
85
  void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
  {
  	/* Unused. */
  }
  EXPORT_SYMBOL(__gcov_merge_ior);
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
86
87
88
89
90
91
92
93
94
95
  /**
   * 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)
  {
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
96
  	struct gcov_info *info = NULL;
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
97
98
99
  
  	mutex_lock(&gcov_lock);
  	gcov_events_enabled = 1;
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
100

2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
101
  	/* Perform event callback for previously registered entries. */
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
102
  	while ((info = gcov_info_next(info)))
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
103
  		gcov_event(GCOV_ADD, info);
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
104

2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  	mutex_unlock(&gcov_lock);
  }
  
  #ifdef CONFIG_MODULES
  static inline int within(void *addr, void *start, unsigned long size)
  {
  	return ((addr >= start) && (addr < start + size));
  }
  
  /* 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;
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
119
120
  	struct gcov_info *info = NULL;
  	struct gcov_info *prev = NULL;
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
121
122
123
124
  
  	if (event != MODULE_STATE_GOING)
  		return NOTIFY_OK;
  	mutex_lock(&gcov_lock);
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
125

2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
126
  	/* Remove entries located in module from linked list. */
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
127
  	while ((info = gcov_info_next(info))) {
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
128
  		if (within(info, mod->module_core, mod->core_size)) {
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
129
  			gcov_info_unlink(prev, info);
2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
130
131
132
133
134
  			if (gcov_events_enabled)
  				gcov_event(GCOV_REMOVE, info);
  		} else
  			prev = info;
  	}
8cbce376e   Frantisek Hrbata   gcov: move gcov s...
135

2521f2c22   Peter Oberparleiter   gcov: add gcov pr...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  	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 */