]>
Commit | Line | Data |
---|---|---|
ded3d3f8 | 1 | /* Routines required for instrumenting a program. */ |
2 | /* Compile this one with gcc. */ | |
fbd26352 | 3 | /* Copyright (C) 1989-2019 Free Software Foundation, Inc. |
ded3d3f8 | 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 | ||
67745126 | 26 | #include "libgcov.h" |
ded3d3f8 | 27 | #include "gthr.h" |
28 | ||
ded3d3f8 | 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 | ||
b12d2330 | 45 | /* Some functions we want to bind in this dynamic object, but have an |
a91625a6 | 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 (); } | |
b12d2330 | 53 | |
859fa1a9 | 54 | extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; |
cb3ea3de | 55 | extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; |
ded3d3f8 | 56 | |
57 | #ifdef L_gcov_flush | |
ded3d3f8 | 58 | #ifdef __GTHREAD_MUTEX_INIT |
cb3ea3de | 59 | __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; |
ded3d3f8 | 60 | #define init_mx_once() |
61 | #else | |
cb3ea3de | 62 | __gthread_mutex_t __gcov_flush_mx; |
ded3d3f8 | 63 | |
64 | static void | |
65 | init_mx (void) | |
66 | { | |
67 | __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); | |
68 | } | |
cb3ea3de | 69 | |
ded3d3f8 | 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 | ||
bc587267 | 88 | __gcov_dump_int (); |
b12d2330 | 89 | __gcov_reset_int (); |
ded3d3f8 | 90 | |
91 | __gthread_mutex_unlock (&__gcov_flush_mx); | |
92 | } | |
93 | ||
94 | #endif /* L_gcov_flush */ | |
95 | ||
96 | #ifdef L_gcov_reset | |
97 | ||
859fa1a9 | 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 | ||
ded3d3f8 | 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 | |
b12d2330 | 133 | __gcov_reset_int (void) |
ded3d3f8 | 134 | { |
bc587267 | 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 | } | |
ded3d3f8 | 145 | } |
146 | ||
a91625a6 | 147 | ALIAS_void_fn (__gcov_reset_int, __gcov_reset); |
b12d2330 | 148 | |
ded3d3f8 | 149 | #endif /* L_gcov_reset */ |
150 | ||
151 | #ifdef L_gcov_dump | |
ded3d3f8 | 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 | |
bc587267 | 156 | __gcov_dump_int (void) |
ded3d3f8 | 157 | { |
bc587267 | 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); | |
ded3d3f8 | 165 | } |
166 | ||
bc587267 | 167 | ALIAS_void_fn (__gcov_dump_int, __gcov_dump); |
168 | ||
ded3d3f8 | 169 | #endif /* L_gcov_dump */ |
170 | ||
ded3d3f8 | 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; | |
ded3d3f8 | 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 | |
bc587267 | 188 | /* A wrapper for the execl function. Flushes the accumulated |
189 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 | |
cb3ea3de | 219 | /* A wrapper for the execlp function. Flushes the accumulated |
220 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 | |
cb3ea3de | 250 | /* A wrapper for the execle function. Flushes the accumulated |
251 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 | |
cb3ea3de | 283 | /* A wrapper for the execv function. Flushes the accumulated |
284 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 | |
cb3ea3de | 295 | /* A wrapper for the execvp function. Flushes the accumulated |
296 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 | |
cb3ea3de | 307 | /* A wrapper for the execve function. Flushes the accumulated |
308 | profiling data, so that they are not lost. */ | |
ded3d3f8 | 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 */ |