testsuite: Skip 90020.c on AIX.
[official-gcc.git] / libgcc / libgcov-interface.c
blob048b9029ff3626f6763422688823ac54c92fdf13
1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2020 Free Software Foundation, Inc.
5 This file is part of GCC.
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.
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.
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.
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/>. */
26 #include "libgcov.h"
27 #include "gthr.h"
29 #if defined(inhibit_libc)
31 #ifdef L_gcov_flush
32 void __gcov_flush (void) {}
33 #endif
35 #ifdef L_gcov_reset
36 void __gcov_reset (void) {}
37 #endif
39 #ifdef L_gcov_dump
40 void __gcov_dump (void) {}
41 #endif
43 #else
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.*/
50 #define ALIAS_void_fn(src,dst) \
51 void dst (void) \
52 { src (); }
54 extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
56 #ifdef L_gcov_flush
57 #ifdef __GTHREAD_MUTEX_INIT
58 __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
59 #define init_mx_once()
60 #else
61 __gthread_mutex_t __gcov_flush_mx;
63 static void
64 init_mx (void)
66 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
69 static void
70 init_mx_once (void)
72 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
73 __gthread_once (&once, init_mx);
75 #endif
77 /* Called before fork or exec - write out profile information gathered so
78 far and reset it to zero. This avoids duplication or loss of the
79 profile information gathered so far. */
81 void
82 __gcov_flush (void)
84 init_mx_once ();
85 __gthread_mutex_lock (&__gcov_flush_mx);
87 __gcov_dump_int ();
88 __gcov_reset_int ();
90 __gthread_mutex_unlock (&__gcov_flush_mx);
93 #endif /* L_gcov_flush */
95 #ifdef L_gcov_reset
97 /* Reset all counters to zero. */
99 static void
100 gcov_clear (const struct gcov_info *list)
102 const struct gcov_info *gi_ptr;
104 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
106 unsigned f_ix;
108 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
110 unsigned t_ix;
111 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
113 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
114 continue;
115 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
116 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
118 if (!gi_ptr->merge[t_ix])
119 continue;
121 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
122 ci_ptr++;
128 /* Function that can be called from application to reset counters to zero,
129 in order to collect profile in region of interest. */
131 void
132 __gcov_reset_int (void)
134 struct gcov_root *root;
136 /* If we're compatible with the master, iterate over everything,
137 otherise just do us. */
138 for (root = __gcov_master.version == GCOV_VERSION
139 ? __gcov_master.root : &__gcov_root; root; root = root->next)
141 gcov_clear (root->list);
142 root->dumped = 0;
146 ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
148 #endif /* L_gcov_reset */
150 #ifdef L_gcov_dump
151 /* Function that can be called from application to write profile collected
152 so far, in order to collect profile in region of interest. */
154 void
155 __gcov_dump_int (void)
157 struct gcov_root *root;
159 /* If we're compatible with the master, iterate over everything,
160 otherise just do us. */
161 for (root = __gcov_master.version == GCOV_VERSION
162 ? __gcov_master.root : &__gcov_root; root; root = root->next)
163 __gcov_dump_one (root);
166 ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
168 #endif /* L_gcov_dump */
170 #ifdef L_gcov_fork
171 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
172 that they are not counted twice. */
174 pid_t
175 __gcov_fork (void)
177 pid_t pid;
178 __gcov_flush ();
179 pid = fork ();
180 if (pid == 0)
181 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
182 return pid;
184 #endif
186 #ifdef L_gcov_execl
187 /* A wrapper for the execl function. Flushes the accumulated
188 profiling data, so that they are not lost. */
191 __gcov_execl (const char *path, char *arg, ...)
193 va_list ap, aq;
194 unsigned i, length;
195 char **args;
197 __gcov_flush ();
199 va_start (ap, arg);
200 va_copy (aq, ap);
202 length = 2;
203 while (va_arg (ap, char *))
204 length++;
205 va_end (ap);
207 args = (char **) alloca (length * sizeof (void *));
208 args[0] = arg;
209 for (i = 1; i < length; i++)
210 args[i] = va_arg (aq, char *);
211 va_end (aq);
213 return execv (path, args);
215 #endif
217 #ifdef L_gcov_execlp
218 /* A wrapper for the execlp function. Flushes the accumulated
219 profiling data, so that they are not lost. */
222 __gcov_execlp (const char *path, char *arg, ...)
224 va_list ap, aq;
225 unsigned i, length;
226 char **args;
228 __gcov_flush ();
230 va_start (ap, arg);
231 va_copy (aq, ap);
233 length = 2;
234 while (va_arg (ap, char *))
235 length++;
236 va_end (ap);
238 args = (char **) alloca (length * sizeof (void *));
239 args[0] = arg;
240 for (i = 1; i < length; i++)
241 args[i] = va_arg (aq, char *);
242 va_end (aq);
244 return execvp (path, args);
246 #endif
248 #ifdef L_gcov_execle
249 /* A wrapper for the execle function. Flushes the accumulated
250 profiling data, so that they are not lost. */
253 __gcov_execle (const char *path, char *arg, ...)
255 va_list ap, aq;
256 unsigned i, length;
257 char **args;
258 char **envp;
260 __gcov_flush ();
262 va_start (ap, arg);
263 va_copy (aq, ap);
265 length = 2;
266 while (va_arg (ap, char *))
267 length++;
268 va_end (ap);
270 args = (char **) alloca (length * sizeof (void *));
271 args[0] = arg;
272 for (i = 1; i < length; i++)
273 args[i] = va_arg (aq, char *);
274 envp = va_arg (aq, char **);
275 va_end (aq);
277 return execve (path, args, envp);
279 #endif
281 #ifdef L_gcov_execv
282 /* A wrapper for the execv function. Flushes the accumulated
283 profiling data, so that they are not lost. */
286 __gcov_execv (const char *path, char *const argv[])
288 __gcov_flush ();
289 return execv (path, argv);
291 #endif
293 #ifdef L_gcov_execvp
294 /* A wrapper for the execvp function. Flushes the accumulated
295 profiling data, so that they are not lost. */
298 __gcov_execvp (const char *path, char *const argv[])
300 __gcov_flush ();
301 return execvp (path, argv);
303 #endif
305 #ifdef L_gcov_execve
306 /* A wrapper for the execve function. Flushes the accumulated
307 profiling data, so that they are not lost. */
310 __gcov_execve (const char *path, char *const argv[], char *const envp[])
312 __gcov_flush ();
313 return execve (path, argv, envp);
315 #endif
316 #endif /* inhibit_libc */