libgcov-interface.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* Routines required for instrumenting a program. */
  2. /* Compile this one with gcc. */
  3. /* Copyright (C) 1989-2022 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_reset
  24. void __gcov_reset (void) {}
  25. #endif
  26. #ifdef L_gcov_dump
  27. void __gcov_dump (void) {}
  28. #endif
  29. #else
  30. extern __gthread_mutex_t __gcov_mx ATTRIBUTE_HIDDEN;
  31. #ifdef L_gcov_lock_unlock
  32. #ifdef __GTHREAD_MUTEX_INIT
  33. __gthread_mutex_t __gcov_mx = __GTHREAD_MUTEX_INIT;
  34. #define init_mx_once()
  35. #else
  36. __gthread_mutex_t __gcov_mx;
  37. static void
  38. init_mx (void)
  39. {
  40. __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_mx);
  41. }
  42. static void
  43. init_mx_once (void)
  44. {
  45. static __gthread_once_t once = __GTHREAD_ONCE_INIT;
  46. __gthread_once (&once, init_mx);
  47. }
  48. #endif
  49. /* Lock critical section for __gcov_dump and __gcov_reset functions. */
  50. void
  51. __gcov_lock (void)
  52. {
  53. init_mx_once ();
  54. __gthread_mutex_lock (&__gcov_mx);
  55. }
  56. /* Unlock critical section for __gcov_dump and __gcov_reset functions. */
  57. void
  58. __gcov_unlock (void)
  59. {
  60. __gthread_mutex_unlock (&__gcov_mx);
  61. }
  62. #endif
  63. #ifdef L_gcov_reset
  64. /* Reset all counters to zero. */
  65. static void
  66. gcov_clear (const struct gcov_info *list)
  67. {
  68. const struct gcov_info *gi_ptr;
  69. for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
  70. {
  71. unsigned f_ix;
  72. for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
  73. {
  74. unsigned t_ix;
  75. const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
  76. if (!gfi_ptr || gfi_ptr->key != gi_ptr)
  77. continue;
  78. const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
  79. for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
  80. {
  81. if (!gi_ptr->merge[t_ix])
  82. continue;
  83. memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
  84. ci_ptr++;
  85. }
  86. }
  87. }
  88. }
  89. /* Function that can be called from application to reset counters to zero,
  90. in order to collect profile in region of interest. */
  91. void
  92. __gcov_reset_int (void)
  93. {
  94. struct gcov_root *root;
  95. /* If we're compatible with the master, iterate over everything,
  96. otherise just do us. */
  97. for (root = __gcov_master.version == GCOV_VERSION
  98. ? __gcov_master.root : &__gcov_root; root; root = root->next)
  99. {
  100. gcov_clear (root->list);
  101. root->dumped = 0;
  102. }
  103. }
  104. /* Exported function __gcov_reset. */
  105. void
  106. __gcov_reset (void)
  107. {
  108. __gcov_lock ();
  109. __gcov_reset_int ();
  110. __gcov_unlock ();
  111. }
  112. #endif /* L_gcov_reset */
  113. #ifdef L_gcov_dump
  114. /* Function that can be called from application to write profile collected
  115. so far, in order to collect profile in region of interest. */
  116. void
  117. __gcov_dump_int (void)
  118. {
  119. struct gcov_root *root;
  120. /* If we're compatible with the master, iterate over everything,
  121. otherise just do us. */
  122. for (root = __gcov_master.version == GCOV_VERSION
  123. ? __gcov_master.root : &__gcov_root; root; root = root->next)
  124. __gcov_dump_one (root);
  125. }
  126. /* Exported function __gcov_dump. */
  127. void
  128. __gcov_dump (void)
  129. {
  130. __gcov_lock ();
  131. __gcov_dump_int ();
  132. __gcov_unlock ();
  133. }
  134. #endif /* L_gcov_dump */
  135. #ifdef L_gcov_fork
  136. /* A wrapper for the fork function. We reset counters in the child
  137. so that they are not counted twice. */
  138. pid_t
  139. __gcov_fork (void)
  140. {
  141. pid_t pid;
  142. pid = fork ();
  143. if (pid == 0)
  144. {
  145. __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_mx);
  146. /* We do not need locking as we are the only thread in the child. */
  147. __gcov_reset_int ();
  148. }
  149. return pid;
  150. }
  151. #endif
  152. #ifdef L_gcov_execl
  153. /* A wrapper for the execl function. Flushes the accumulated
  154. profiling data, so that they are not lost. */
  155. int
  156. __gcov_execl (const char *path, char *arg, ...)
  157. {
  158. va_list ap, aq;
  159. unsigned i, length;
  160. char **args;
  161. /* Dump counters only, they will be lost after exec. */
  162. __gcov_dump ();
  163. va_start (ap, arg);
  164. va_copy (aq, ap);
  165. length = 2;
  166. while (va_arg (ap, char *))
  167. length++;
  168. va_end (ap);
  169. args = (char **) alloca (length * sizeof (void *));
  170. args[0] = arg;
  171. for (i = 1; i < length; i++)
  172. args[i] = va_arg (aq, char *);
  173. va_end (aq);
  174. int ret = execv (path, args);
  175. /* We reach this code only when execv fails, reset counter then here. */
  176. __gcov_reset ();
  177. return ret;
  178. }
  179. #endif
  180. #ifdef L_gcov_execlp
  181. /* A wrapper for the execlp function. Flushes the accumulated
  182. profiling data, so that they are not lost. */
  183. int
  184. __gcov_execlp (const char *path, char *arg, ...)
  185. {
  186. va_list ap, aq;
  187. unsigned i, length;
  188. char **args;
  189. /* Dump counters only, they will be lost after exec. */
  190. __gcov_dump ();
  191. va_start (ap, arg);
  192. va_copy (aq, ap);
  193. length = 2;
  194. while (va_arg (ap, char *))
  195. length++;
  196. va_end (ap);
  197. args = (char **) alloca (length * sizeof (void *));
  198. args[0] = arg;
  199. for (i = 1; i < length; i++)
  200. args[i] = va_arg (aq, char *);
  201. va_end (aq);
  202. int ret = execvp (path, args);
  203. /* We reach this code only when execv fails, reset counter then here. */
  204. __gcov_reset ();
  205. return ret;
  206. }
  207. #endif
  208. #ifdef L_gcov_execle
  209. /* A wrapper for the execle function. Flushes the accumulated
  210. profiling data, so that they are not lost. */
  211. int
  212. __gcov_execle (const char *path, char *arg, ...)
  213. {
  214. va_list ap, aq;
  215. unsigned i, length;
  216. char **args;
  217. char **envp;
  218. /* Dump counters only, they will be lost after exec. */
  219. __gcov_dump ();
  220. va_start (ap, arg);
  221. va_copy (aq, ap);
  222. length = 2;
  223. while (va_arg (ap, char *))
  224. length++;
  225. va_end (ap);
  226. args = (char **) alloca (length * sizeof (void *));
  227. args[0] = arg;
  228. for (i = 1; i < length; i++)
  229. args[i] = va_arg (aq, char *);
  230. envp = va_arg (aq, char **);
  231. va_end (aq);
  232. int ret = execve (path, args, envp);
  233. /* We reach this code only when execv fails, reset counter then here. */
  234. __gcov_reset ();
  235. return ret;
  236. }
  237. #endif
  238. #ifdef L_gcov_execv
  239. /* A wrapper for the execv function. Flushes the accumulated
  240. profiling data, so that they are not lost. */
  241. int
  242. __gcov_execv (const char *path, char *const argv[])
  243. {
  244. /* Dump counters only, they will be lost after exec. */
  245. __gcov_dump ();
  246. int ret = execv (path, argv);
  247. /* We reach this code only when execv fails, reset counter then here. */
  248. __gcov_reset ();
  249. return ret;
  250. }
  251. #endif
  252. #ifdef L_gcov_execvp
  253. /* A wrapper for the execvp function. Flushes the accumulated
  254. profiling data, so that they are not lost. */
  255. int
  256. __gcov_execvp (const char *path, char *const argv[])
  257. {
  258. /* Dump counters only, they will be lost after exec. */
  259. __gcov_dump ();
  260. int ret = execvp (path, argv);
  261. /* We reach this code only when execv fails, reset counter then here. */
  262. __gcov_reset ();
  263. return ret;
  264. }
  265. #endif
  266. #ifdef L_gcov_execve
  267. /* A wrapper for the execve function. Flushes the accumulated
  268. profiling data, so that they are not lost. */
  269. int
  270. __gcov_execve (const char *path, char *const argv[], char *const envp[])
  271. {
  272. /* Dump counters only, they will be lost after exec. */
  273. __gcov_dump ();
  274. int ret = execve (path, argv, envp);
  275. /* We reach this code only when execv fails, reset counter then here. */
  276. __gcov_reset ();
  277. return ret;
  278. }
  279. #endif
  280. #endif /* inhibit_libc */