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