Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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