libgcov-interface.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /* Routines required for instrumenting a program. */
  2. /* Compile this one with gcc. */
  3. /* Copyright (C) 1989-2015 Free Software Foundation, Inc.
  4. This file is part of GCC.
  5. GCC is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 3, or (at your option) any later
  8. version.
  9. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. #include "libgcov.h"
  21. #include "gthr.h"
  22. #if defined(inhibit_libc)
  23. #ifdef L_gcov_flush
  24. void __gcov_flush (void) {}
  25. #endif
  26. #ifdef L_gcov_reset
  27. void __gcov_reset (void) {}
  28. #endif
  29. #ifdef L_gcov_dump
  30. void __gcov_dump (void) {}
  31. #endif
  32. #else
  33. /* Some functions we want to bind in this dynamic object, but have an
  34. overridable global alias. Unfortunately not all targets support
  35. aliases, so we just have a forwarding function. That'll be tail
  36. called, so the cost is a single jump instruction.*/
  37. #define ALIAS_void_fn(src,dst) \
  38. void dst (void) \
  39. { src (); }
  40. extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
  41. extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
  42. #ifdef L_gcov_flush
  43. #ifdef __GTHREAD_MUTEX_INIT
  44. __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
  45. #define init_mx_once()
  46. #else
  47. __gthread_mutex_t __gcov_flush_mx;
  48. static void
  49. init_mx (void)
  50. {
  51. __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
  52. }
  53. static void
  54. init_mx_once (void)
  55. {
  56. static __gthread_once_t once = __GTHREAD_ONCE_INIT;
  57. __gthread_once (&once, init_mx);
  58. }
  59. #endif
  60. /* Called before fork or exec - write out profile information gathered so
  61. far and reset it to zero. This avoids duplication or loss of the
  62. profile information gathered so far. */
  63. void
  64. __gcov_flush (void)
  65. {
  66. init_mx_once ();
  67. __gthread_mutex_lock (&__gcov_flush_mx);
  68. __gcov_dump_int ();
  69. __gcov_reset_int ();
  70. __gthread_mutex_unlock (&__gcov_flush_mx);
  71. }
  72. #endif /* L_gcov_flush */
  73. #ifdef L_gcov_reset
  74. /* Reset all counters to zero. */
  75. static void
  76. gcov_clear (const struct gcov_info *list)
  77. {
  78. const struct gcov_info *gi_ptr;
  79. for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
  80. {
  81. unsigned f_ix;
  82. for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
  83. {
  84. unsigned t_ix;
  85. const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
  86. if (!gfi_ptr || gfi_ptr->key != gi_ptr)
  87. continue;
  88. const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
  89. for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
  90. {
  91. if (!gi_ptr->merge[t_ix])
  92. continue;
  93. memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
  94. ci_ptr++;
  95. }
  96. }
  97. }
  98. }
  99. /* Function that can be called from application to reset counters to zero,
  100. in order to collect profile in region of interest. */
  101. void
  102. __gcov_reset_int (void)
  103. {
  104. struct gcov_root *root;
  105. /* If we're compatible with the master, iterate over everything,
  106. otherise just do us. */
  107. for (root = __gcov_master.version == GCOV_VERSION
  108. ? __gcov_master.root : &__gcov_root; root; root = root->next)
  109. {
  110. gcov_clear (root->list);
  111. root->dumped = 0;
  112. }
  113. }
  114. ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
  115. #endif /* L_gcov_reset */
  116. #ifdef L_gcov_dump
  117. /* Function that can be called from application to write profile collected
  118. so far, in order to collect profile in region of interest. */
  119. void
  120. __gcov_dump_int (void)
  121. {
  122. struct gcov_root *root;
  123. /* If we're compatible with the master, iterate over everything,
  124. otherise just do us. */
  125. for (root = __gcov_master.version == GCOV_VERSION
  126. ? __gcov_master.root : &__gcov_root; root; root = root->next)
  127. __gcov_dump_one (root);
  128. }
  129. ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
  130. #endif /* L_gcov_dump */
  131. #ifdef L_gcov_fork
  132. /* A wrapper for the fork function. Flushes the accumulated profiling data, so
  133. that they are not counted twice. */
  134. pid_t
  135. __gcov_fork (void)
  136. {
  137. pid_t pid;
  138. __gcov_flush ();
  139. pid = fork ();
  140. if (pid == 0)
  141. __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
  142. return pid;
  143. }
  144. #endif
  145. #ifdef L_gcov_execl
  146. /* A wrapper for the execl function. Flushes the accumulated
  147. profiling data, so that they are not lost. */
  148. int
  149. __gcov_execl (const char *path, char *arg, ...)
  150. {
  151. va_list ap, aq;
  152. unsigned i, length;
  153. char **args;
  154. __gcov_flush ();
  155. va_start (ap, arg);
  156. va_copy (aq, ap);
  157. length = 2;
  158. while (va_arg (ap, char *))
  159. length++;
  160. va_end (ap);
  161. args = (char **) alloca (length * sizeof (void *));
  162. args[0] = arg;
  163. for (i = 1; i < length; i++)
  164. args[i] = va_arg (aq, char *);
  165. va_end (aq);
  166. return execv (path, args);
  167. }
  168. #endif
  169. #ifdef L_gcov_execlp
  170. /* A wrapper for the execlp function. Flushes the accumulated
  171. profiling data, so that they are not lost. */
  172. int
  173. __gcov_execlp (const char *path, char *arg, ...)
  174. {
  175. va_list ap, aq;
  176. unsigned i, length;
  177. char **args;
  178. __gcov_flush ();
  179. va_start (ap, arg);
  180. va_copy (aq, ap);
  181. length = 2;
  182. while (va_arg (ap, char *))
  183. length++;
  184. va_end (ap);
  185. args = (char **) alloca (length * sizeof (void *));
  186. args[0] = arg;
  187. for (i = 1; i < length; i++)
  188. args[i] = va_arg (aq, char *);
  189. va_end (aq);
  190. return execvp (path, args);
  191. }
  192. #endif
  193. #ifdef L_gcov_execle
  194. /* A wrapper for the execle function. Flushes the accumulated
  195. profiling data, so that they are not lost. */
  196. int
  197. __gcov_execle (const char *path, char *arg, ...)
  198. {
  199. va_list ap, aq;
  200. unsigned i, length;
  201. char **args;
  202. char **envp;
  203. __gcov_flush ();
  204. va_start (ap, arg);
  205. va_copy (aq, ap);
  206. length = 2;
  207. while (va_arg (ap, char *))
  208. length++;
  209. va_end (ap);
  210. args = (char **) alloca (length * sizeof (void *));
  211. args[0] = arg;
  212. for (i = 1; i < length; i++)
  213. args[i] = va_arg (aq, char *);
  214. envp = va_arg (aq, char **);
  215. va_end (aq);
  216. return execve (path, args, envp);
  217. }
  218. #endif
  219. #ifdef L_gcov_execv
  220. /* A wrapper for the execv function. Flushes the accumulated
  221. profiling data, so that they are not lost. */
  222. int
  223. __gcov_execv (const char *path, char *const argv[])
  224. {
  225. __gcov_flush ();
  226. return execv (path, argv);
  227. }
  228. #endif
  229. #ifdef L_gcov_execvp
  230. /* A wrapper for the execvp function. Flushes the accumulated
  231. profiling data, so that they are not lost. */
  232. int
  233. __gcov_execvp (const char *path, char *const argv[])
  234. {
  235. __gcov_flush ();
  236. return execvp (path, argv);
  237. }
  238. #endif
  239. #ifdef L_gcov_execve
  240. /* A wrapper for the execve function. Flushes the accumulated
  241. profiling data, so that they are not lost. */
  242. int
  243. __gcov_execve (const char *path, char *const argv[], char *const envp[])
  244. {
  245. __gcov_flush ();
  246. return execve (path, argv, envp);
  247. }
  248. #endif
  249. #endif /* inhibit_libc */