base.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * This code maintains a list of active profiling data structures.
  3. *
  4. * Copyright IBM Corp. 2009
  5. * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
  6. *
  7. * Uses gcc-internal data definitions.
  8. * Based on the gcov-kernel patch by:
  9. * Hubertus Franke <frankeh@us.ibm.com>
  10. * Nigel Hinds <nhinds@us.ibm.com>
  11. * Rajan Ravindran <rajancr@us.ibm.com>
  12. * Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
  13. * Paul Larson
  14. */
  15. #define pr_fmt(fmt) "gcov: " fmt
  16. #include <linux/init.h>
  17. #include <linux/module.h>
  18. #include <linux/mutex.h>
  19. #include "gcov.h"
  20. static int gcov_events_enabled;
  21. static DEFINE_MUTEX(gcov_lock);
  22. /*
  23. * __gcov_init is called by gcc-generated constructor code for each object
  24. * file compiled with -fprofile-arcs.
  25. */
  26. void __gcov_init(struct gcov_info *info)
  27. {
  28. static unsigned int gcov_version;
  29. mutex_lock(&gcov_lock);
  30. if (gcov_version == 0) {
  31. gcov_version = gcov_info_version(info);
  32. /*
  33. * Printing gcc's version magic may prove useful for debugging
  34. * incompatibility reports.
  35. */
  36. pr_info("version magic: 0x%x\n", gcov_version);
  37. }
  38. /*
  39. * Add new profiling data structure to list and inform event
  40. * listener.
  41. */
  42. gcov_info_link(info);
  43. if (gcov_events_enabled)
  44. gcov_event(GCOV_ADD, info);
  45. mutex_unlock(&gcov_lock);
  46. }
  47. EXPORT_SYMBOL(__gcov_init);
  48. /*
  49. * These functions may be referenced by gcc-generated profiling code but serve
  50. * no function for kernel profiling.
  51. */
  52. void __gcov_flush(void)
  53. {
  54. /* Unused. */
  55. }
  56. EXPORT_SYMBOL(__gcov_flush);
  57. void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
  58. {
  59. /* Unused. */
  60. }
  61. EXPORT_SYMBOL(__gcov_merge_add);
  62. void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
  63. {
  64. /* Unused. */
  65. }
  66. EXPORT_SYMBOL(__gcov_merge_single);
  67. void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
  68. {
  69. /* Unused. */
  70. }
  71. EXPORT_SYMBOL(__gcov_merge_delta);
  72. void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
  73. {
  74. /* Unused. */
  75. }
  76. EXPORT_SYMBOL(__gcov_merge_ior);
  77. void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters)
  78. {
  79. /* Unused. */
  80. }
  81. EXPORT_SYMBOL(__gcov_merge_time_profile);
  82. /**
  83. * gcov_enable_events - enable event reporting through gcov_event()
  84. *
  85. * Turn on reporting of profiling data load/unload-events through the
  86. * gcov_event() callback. Also replay all previous events once. This function
  87. * is needed because some events are potentially generated too early for the
  88. * callback implementation to handle them initially.
  89. */
  90. void gcov_enable_events(void)
  91. {
  92. struct gcov_info *info = NULL;
  93. mutex_lock(&gcov_lock);
  94. gcov_events_enabled = 1;
  95. /* Perform event callback for previously registered entries. */
  96. while ((info = gcov_info_next(info)))
  97. gcov_event(GCOV_ADD, info);
  98. mutex_unlock(&gcov_lock);
  99. }
  100. #ifdef CONFIG_MODULES
  101. static inline int within(void *addr, void *start, unsigned long size)
  102. {
  103. return ((addr >= start) && (addr < start + size));
  104. }
  105. /* Update list and generate events when modules are unloaded. */
  106. static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
  107. void *data)
  108. {
  109. struct module *mod = data;
  110. struct gcov_info *info = NULL;
  111. struct gcov_info *prev = NULL;
  112. if (event != MODULE_STATE_GOING)
  113. return NOTIFY_OK;
  114. mutex_lock(&gcov_lock);
  115. /* Remove entries located in module from linked list. */
  116. while ((info = gcov_info_next(info))) {
  117. if (within(info, mod->module_core, mod->core_size)) {
  118. gcov_info_unlink(prev, info);
  119. if (gcov_events_enabled)
  120. gcov_event(GCOV_REMOVE, info);
  121. } else
  122. prev = info;
  123. }
  124. mutex_unlock(&gcov_lock);
  125. return NOTIFY_OK;
  126. }
  127. static struct notifier_block gcov_nb = {
  128. .notifier_call = gcov_module_notifier,
  129. };
  130. static int __init gcov_init(void)
  131. {
  132. return register_module_notifier(&gcov_nb);
  133. }
  134. device_initcall(gcov_init);
  135. #endif /* CONFIG_MODULES */