base.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. #define pr_fmt(fmt) "gcov: " fmt
  17. #include <linux/init.h>
  18. #include <linux/module.h>
  19. #include <linux/mutex.h>
  20. #include <linux/sched.h>
  21. #include "gcov.h"
  22. static int gcov_events_enabled;
  23. static DEFINE_MUTEX(gcov_lock);
  24. /*
  25. * __gcov_init is called by gcc-generated constructor code for each object
  26. * file compiled with -fprofile-arcs.
  27. */
  28. void __gcov_init(struct gcov_info *info)
  29. {
  30. static unsigned int gcov_version;
  31. mutex_lock(&gcov_lock);
  32. if (gcov_version == 0) {
  33. gcov_version = gcov_info_version(info);
  34. /*
  35. * Printing gcc's version magic may prove useful for debugging
  36. * incompatibility reports.
  37. */
  38. pr_info("version magic: 0x%x\n", gcov_version);
  39. }
  40. /*
  41. * Add new profiling data structure to list and inform event
  42. * listener.
  43. */
  44. gcov_info_link(info);
  45. if (gcov_events_enabled)
  46. gcov_event(GCOV_ADD, info);
  47. mutex_unlock(&gcov_lock);
  48. }
  49. EXPORT_SYMBOL(__gcov_init);
  50. /*
  51. * These functions may be referenced by gcc-generated profiling code but serve
  52. * no function for kernel profiling.
  53. */
  54. void __gcov_flush(void)
  55. {
  56. /* Unused. */
  57. }
  58. EXPORT_SYMBOL(__gcov_flush);
  59. void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
  60. {
  61. /* Unused. */
  62. }
  63. EXPORT_SYMBOL(__gcov_merge_add);
  64. void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
  65. {
  66. /* Unused. */
  67. }
  68. EXPORT_SYMBOL(__gcov_merge_single);
  69. void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
  70. {
  71. /* Unused. */
  72. }
  73. EXPORT_SYMBOL(__gcov_merge_delta);
  74. void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
  75. {
  76. /* Unused. */
  77. }
  78. EXPORT_SYMBOL(__gcov_merge_ior);
  79. void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters)
  80. {
  81. /* Unused. */
  82. }
  83. EXPORT_SYMBOL(__gcov_merge_time_profile);
  84. void __gcov_merge_icall_topn(gcov_type *counters, unsigned int n_counters)
  85. {
  86. /* Unused. */
  87. }
  88. EXPORT_SYMBOL(__gcov_merge_icall_topn);
  89. void __gcov_exit(void)
  90. {
  91. /* Unused. */
  92. }
  93. EXPORT_SYMBOL(__gcov_exit);
  94. /**
  95. * gcov_enable_events - enable event reporting through gcov_event()
  96. *
  97. * Turn on reporting of profiling data load/unload-events through the
  98. * gcov_event() callback. Also replay all previous events once. This function
  99. * is needed because some events are potentially generated too early for the
  100. * callback implementation to handle them initially.
  101. */
  102. void gcov_enable_events(void)
  103. {
  104. struct gcov_info *info = NULL;
  105. mutex_lock(&gcov_lock);
  106. gcov_events_enabled = 1;
  107. /* Perform event callback for previously registered entries. */
  108. while ((info = gcov_info_next(info))) {
  109. gcov_event(GCOV_ADD, info);
  110. cond_resched();
  111. }
  112. mutex_unlock(&gcov_lock);
  113. }
  114. #ifdef CONFIG_MODULES
  115. /* Update list and generate events when modules are unloaded. */
  116. static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
  117. void *data)
  118. {
  119. struct module *mod = data;
  120. struct gcov_info *info = NULL;
  121. struct gcov_info *prev = NULL;
  122. if (event != MODULE_STATE_GOING)
  123. return NOTIFY_OK;
  124. mutex_lock(&gcov_lock);
  125. /* Remove entries located in module from linked list. */
  126. while ((info = gcov_info_next(info))) {
  127. if (within_module((unsigned long)info, mod)) {
  128. gcov_info_unlink(prev, info);
  129. if (gcov_events_enabled)
  130. gcov_event(GCOV_REMOVE, info);
  131. } else
  132. prev = info;
  133. }
  134. mutex_unlock(&gcov_lock);
  135. return NOTIFY_OK;
  136. }
  137. static struct notifier_block gcov_nb = {
  138. .notifier_call = gcov_module_notifier,
  139. };
  140. static int __init gcov_init(void)
  141. {
  142. return register_module_notifier(&gcov_nb);
  143. }
  144. device_initcall(gcov_init);
  145. #endif /* CONFIG_MODULES */