base.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 struct gcov_info *gcov_info_head;
  21. static int gcov_events_enabled;
  22. static DEFINE_MUTEX(gcov_lock);
  23. /*
  24. * __gcov_init is called by gcc-generated constructor code for each object
  25. * file compiled with -fprofile-arcs.
  26. */
  27. void __gcov_init(struct gcov_info *info)
  28. {
  29. static unsigned int gcov_version;
  30. mutex_lock(&gcov_lock);
  31. if (gcov_version == 0) {
  32. gcov_version = info->version;
  33. /*
  34. * Printing gcc's version magic may prove useful for debugging
  35. * incompatibility reports.
  36. */
  37. pr_info("version magic: 0x%x\n", gcov_version);
  38. }
  39. /*
  40. * Add new profiling data structure to list and inform event
  41. * listener.
  42. */
  43. info->next = gcov_info_head;
  44. gcov_info_head = 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. /**
  75. * gcov_enable_events - enable event reporting through gcov_event()
  76. *
  77. * Turn on reporting of profiling data load/unload-events through the
  78. * gcov_event() callback. Also replay all previous events once. This function
  79. * is needed because some events are potentially generated too early for the
  80. * callback implementation to handle them initially.
  81. */
  82. void gcov_enable_events(void)
  83. {
  84. struct gcov_info *info;
  85. mutex_lock(&gcov_lock);
  86. gcov_events_enabled = 1;
  87. /* Perform event callback for previously registered entries. */
  88. for (info = gcov_info_head; info; info = info->next)
  89. gcov_event(GCOV_ADD, info);
  90. mutex_unlock(&gcov_lock);
  91. }
  92. #ifdef CONFIG_MODULES
  93. static inline int within(void *addr, void *start, unsigned long size)
  94. {
  95. return ((addr >= start) && (addr < start + size));
  96. }
  97. /* Update list and generate events when modules are unloaded. */
  98. static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
  99. void *data)
  100. {
  101. struct module *mod = data;
  102. struct gcov_info *info;
  103. struct gcov_info *prev;
  104. if (event != MODULE_STATE_GOING)
  105. return NOTIFY_OK;
  106. mutex_lock(&gcov_lock);
  107. prev = NULL;
  108. /* Remove entries located in module from linked list. */
  109. for (info = gcov_info_head; info; info = info->next) {
  110. if (within(info, mod->module_core, mod->core_size)) {
  111. if (prev)
  112. prev->next = info->next;
  113. else
  114. gcov_info_head = info->next;
  115. if (gcov_events_enabled)
  116. gcov_event(GCOV_REMOVE, info);
  117. } else
  118. prev = info;
  119. }
  120. mutex_unlock(&gcov_lock);
  121. return NOTIFY_OK;
  122. }
  123. static struct notifier_block gcov_nb = {
  124. .notifier_call = gcov_module_notifier,
  125. };
  126. static int __init gcov_init(void)
  127. {
  128. return register_module_notifier(&gcov_nb);
  129. }
  130. device_initcall(gcov_init);
  131. #endif /* CONFIG_MODULES */