base.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. #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. int gcov_events_enabled;
  23. DEFINE_MUTEX(gcov_lock);
  24. /**
  25. * gcov_enable_events - enable event reporting through gcov_event()
  26. *
  27. * Turn on reporting of profiling data load/unload-events through the
  28. * gcov_event() callback. Also replay all previous events once. This function
  29. * is needed because some events are potentially generated too early for the
  30. * callback implementation to handle them initially.
  31. */
  32. void gcov_enable_events(void)
  33. {
  34. struct gcov_info *info = NULL;
  35. mutex_lock(&gcov_lock);
  36. gcov_events_enabled = 1;
  37. /* Perform event callback for previously registered entries. */
  38. while ((info = gcov_info_next(info))) {
  39. gcov_event(GCOV_ADD, info);
  40. cond_resched();
  41. }
  42. mutex_unlock(&gcov_lock);
  43. }
  44. /**
  45. * store_gcov_u32 - store 32 bit number in gcov format to buffer
  46. * @buffer: target buffer or NULL
  47. * @off: offset into the buffer
  48. * @v: value to be stored
  49. *
  50. * Number format defined by gcc: numbers are recorded in the 32 bit
  51. * unsigned binary form of the endianness of the machine generating the
  52. * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
  53. * store anything.
  54. */
  55. size_t store_gcov_u32(void *buffer, size_t off, u32 v)
  56. {
  57. u32 *data;
  58. if (buffer) {
  59. data = buffer + off;
  60. *data = v;
  61. }
  62. return sizeof(*data);
  63. }
  64. /**
  65. * store_gcov_u64 - store 64 bit number in gcov format to buffer
  66. * @buffer: target buffer or NULL
  67. * @off: offset into the buffer
  68. * @v: value to be stored
  69. *
  70. * Number format defined by gcc: numbers are recorded in the 32 bit
  71. * unsigned binary form of the endianness of the machine generating the
  72. * file. 64 bit numbers are stored as two 32 bit numbers, the low part
  73. * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
  74. * anything.
  75. */
  76. size_t store_gcov_u64(void *buffer, size_t off, u64 v)
  77. {
  78. u32 *data;
  79. if (buffer) {
  80. data = buffer + off;
  81. data[0] = (v & 0xffffffffUL);
  82. data[1] = (v >> 32);
  83. }
  84. return sizeof(*data) * 2;
  85. }
  86. #ifdef CONFIG_MODULES
  87. /* Update list and generate events when modules are unloaded. */
  88. static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
  89. void *data)
  90. {
  91. struct module *mod = data;
  92. struct gcov_info *info = NULL;
  93. struct gcov_info *prev = NULL;
  94. if (event != MODULE_STATE_GOING)
  95. return NOTIFY_OK;
  96. mutex_lock(&gcov_lock);
  97. /* Remove entries located in module from linked list. */
  98. while ((info = gcov_info_next(info))) {
  99. if (gcov_info_within_module(info, mod)) {
  100. gcov_info_unlink(prev, info);
  101. if (gcov_events_enabled)
  102. gcov_event(GCOV_REMOVE, info);
  103. } else
  104. prev = info;
  105. }
  106. mutex_unlock(&gcov_lock);
  107. return NOTIFY_OK;
  108. }
  109. static struct notifier_block gcov_nb = {
  110. .notifier_call = gcov_module_notifier,
  111. };
  112. static int __init gcov_init(void)
  113. {
  114. return register_module_notifier(&gcov_nb);
  115. }
  116. device_initcall(gcov_init);
  117. #endif /* CONFIG_MODULES */