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