gcov_subr.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Copyright (c) 2019, Matthew Macy <mmacy@freebsd.org>
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. *
  27. */
  28. #include <sys/cdefs.h>
  29. __FBSDID("$FreeBSD$");
  30. #include <sys/types.h>
  31. #include <sys/systm.h>
  32. #include <sys/param.h>
  33. #include <sys/sbuf.h>
  34. #include <sys/queue.h>
  35. #include <sys/linker.h>
  36. #include <sys/module.h>
  37. #include <sys/eventhandler.h>
  38. #include <sys/kernel.h>
  39. #include <sys/malloc.h>
  40. #include <sys/syslog.h>
  41. #include <sys/proc.h>
  42. #include <sys/sched.h>
  43. #include <sys/syslog.h>
  44. #include <sys/sysctl.h>
  45. #include <gnu/gcov/gcov.h>
  46. #include <sys/queue.h>
  47. #include "linker_if.h"
  48. static void gcov_invoke_ctors(void);
  49. static int gcov_ctors_done;
  50. int gcov_events_enabled;
  51. static int
  52. gcov_stats_reset_sysctl(SYSCTL_HANDLER_ARGS)
  53. {
  54. int error, v;
  55. v = 0;
  56. error = sysctl_handle_int(oidp, &v, 0, req);
  57. if (error)
  58. return (error);
  59. if (req->newptr == NULL)
  60. return (error);
  61. if (v == 0)
  62. return (0);
  63. gcov_stats_reset();
  64. return (0);
  65. }
  66. static int
  67. gcov_stats_enable_sysctl(SYSCTL_HANDLER_ARGS)
  68. {
  69. int error, v;
  70. v = gcov_events_enabled;
  71. error = sysctl_handle_int(oidp, &v, v, req);
  72. if (error)
  73. return (error);
  74. if (req->newptr == NULL)
  75. return (error);
  76. if (v == gcov_events_enabled)
  77. return (0);
  78. //gcov_events_reset();
  79. gcov_events_enabled = !!v;
  80. if (!gcov_ctors_done)
  81. gcov_invoke_ctors();
  82. if (gcov_events_enabled)
  83. gcov_enable_events();
  84. return (0);
  85. }
  86. int
  87. within_module(vm_offset_t addr, module_t mod)
  88. {
  89. linker_file_t link_info;
  90. vm_offset_t mod_addr;
  91. size_t mod_size;
  92. link_info = module_file(mod);
  93. mod_addr = (vm_offset_t)link_info->address;
  94. mod_size = link_info->size;
  95. if (addr >= mod_addr && addr < mod_addr + mod_size)
  96. return (1);
  97. return (0);
  98. }
  99. #define GCOV_PREFIX "_GLOBAL__sub_I_65535_0_"
  100. static int
  101. gcov_invoke_ctor(const char *name, void *arg)
  102. {
  103. void (*ctor)(void);
  104. c_linker_sym_t sym;
  105. linker_symval_t symval;
  106. linker_file_t lf;
  107. if (strstr(name, GCOV_PREFIX) == NULL)
  108. return (0);
  109. lf = arg;
  110. LINKER_LOOKUP_SYMBOL(lf, name, &sym);
  111. LINKER_SYMBOL_VALUES(lf, sym, &symval);
  112. ctor = (void *)symval.value;
  113. ctor();
  114. return (0);
  115. }
  116. static int
  117. gcov_invoke_lf_ctors(linker_file_t lf, void *arg __unused)
  118. {
  119. printf("%s processing file: %s\n", __func__, lf->filename);
  120. LINKER_EACH_FUNCTION_NAME(lf, gcov_invoke_ctor, lf);
  121. return (0);
  122. }
  123. static void
  124. gcov_invoke_ctors(void)
  125. {
  126. gcov_fs_init();
  127. linker_file_foreach(gcov_invoke_lf_ctors, NULL);
  128. gcov_ctors_done = 1;
  129. }
  130. static int
  131. gcov_init(void *arg __unused)
  132. {
  133. EVENTHANDLER_REGISTER(module_unload, gcov_module_unload, NULL, 0);
  134. gcov_enable_events();
  135. return (0);
  136. }
  137. SYSINIT(gcov_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, gcov_init, NULL);
  138. static SYSCTL_NODE(_debug, OID_AUTO, gcov, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
  139. "gcov code coverage");
  140. SYSCTL_PROC(_debug_gcov, OID_AUTO, reset,
  141. CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  142. gcov_stats_reset_sysctl, "I",
  143. "Reset all profiling counts");
  144. SYSCTL_PROC(_debug_gcov, OID_AUTO, enable,
  145. CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  146. gcov_stats_enable_sysctl, "I",
  147. "Enable code coverage");