]>
Commit | Line | Data |
---|---|---|
d6d3f033 RX |
1 | /* Routines required for instrumenting a program. */ |
2 | /* Compile this one with gcc. */ | |
8d9254fc | 3 | /* Copyright (C) 1989-2020 Free Software Foundation, Inc. |
d6d3f033 RX |
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 | ||
40d6b753 | 26 | #include "libgcov.h" |
d6d3f033 RX |
27 | #include "gthr.h" |
28 | ||
d6d3f033 RX |
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 | ||
b20ee094 | 45 | /* Some functions we want to bind in this dynamic object, but have an |
71c3e2ef NS |
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 (); } | |
b20ee094 | 53 | |
4303c581 | 54 | extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; |
d6d3f033 RX |
55 | |
56 | #ifdef L_gcov_flush | |
d6d3f033 | 57 | #ifdef __GTHREAD_MUTEX_INIT |
b98a872b | 58 | __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; |
d6d3f033 RX |
59 | #define init_mx_once() |
60 | #else | |
b98a872b | 61 | __gthread_mutex_t __gcov_flush_mx; |
d6d3f033 RX |
62 | |
63 | static void | |
64 | init_mx (void) | |
65 | { | |
66 | __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); | |
67 | } | |
b98a872b | 68 | |
d6d3f033 RX |
69 | static void |
70 | init_mx_once (void) | |
71 | { | |
72 | static __gthread_once_t once = __GTHREAD_ONCE_INIT; | |
73 | __gthread_once (&once, init_mx); | |
74 | } | |
75 | #endif | |
76 | ||
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. */ | |
80 | ||
81 | void | |
82 | __gcov_flush (void) | |
83 | { | |
84 | init_mx_once (); | |
85 | __gthread_mutex_lock (&__gcov_flush_mx); | |
86 | ||
cadb2b96 | 87 | __gcov_dump_int (); |
b20ee094 | 88 | __gcov_reset_int (); |
d6d3f033 RX |
89 | |
90 | __gthread_mutex_unlock (&__gcov_flush_mx); | |
91 | } | |
92 | ||
93 | #endif /* L_gcov_flush */ | |
94 | ||
95 | #ifdef L_gcov_reset | |
96 | ||
4303c581 NS |
97 | /* Reset all counters to zero. */ |
98 | ||
99 | static void | |
100 | gcov_clear (const struct gcov_info *list) | |
101 | { | |
102 | const struct gcov_info *gi_ptr; | |
103 | ||
104 | for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) | |
105 | { | |
106 | unsigned f_ix; | |
107 | ||
108 | for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) | |
109 | { | |
110 | unsigned t_ix; | |
111 | const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; | |
112 | ||
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++) | |
117 | { | |
118 | if (!gi_ptr->merge[t_ix]) | |
119 | continue; | |
120 | ||
121 | memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); | |
122 | ci_ptr++; | |
123 | } | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
d6d3f033 RX |
128 | /* Function that can be called from application to reset counters to zero, |
129 | in order to collect profile in region of interest. */ | |
130 | ||
131 | void | |
b20ee094 | 132 | __gcov_reset_int (void) |
d6d3f033 | 133 | { |
cadb2b96 NS |
134 | struct gcov_root *root; |
135 | ||
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) | |
140 | { | |
141 | gcov_clear (root->list); | |
142 | root->dumped = 0; | |
143 | } | |
d6d3f033 RX |
144 | } |
145 | ||
71c3e2ef | 146 | ALIAS_void_fn (__gcov_reset_int, __gcov_reset); |
b20ee094 | 147 | |
d6d3f033 RX |
148 | #endif /* L_gcov_reset */ |
149 | ||
150 | #ifdef L_gcov_dump | |
d6d3f033 RX |
151 | /* Function that can be called from application to write profile collected |
152 | so far, in order to collect profile in region of interest. */ | |
153 | ||
154 | void | |
cadb2b96 | 155 | __gcov_dump_int (void) |
d6d3f033 | 156 | { |
cadb2b96 NS |
157 | struct gcov_root *root; |
158 | ||
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); | |
d6d3f033 RX |
164 | } |
165 | ||
cadb2b96 NS |
166 | ALIAS_void_fn (__gcov_dump_int, __gcov_dump); |
167 | ||
d6d3f033 RX |
168 | #endif /* L_gcov_dump */ |
169 | ||
d6d3f033 RX |
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. */ | |
173 | ||
174 | pid_t | |
175 | __gcov_fork (void) | |
176 | { | |
177 | pid_t pid; | |
d6d3f033 RX |
178 | __gcov_flush (); |
179 | pid = fork (); | |
180 | if (pid == 0) | |
181 | __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); | |
182 | return pid; | |
183 | } | |
184 | #endif | |
185 | ||
186 | #ifdef L_gcov_execl | |
cadb2b96 NS |
187 | /* A wrapper for the execl function. Flushes the accumulated |
188 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
189 | |
190 | int | |
191 | __gcov_execl (const char *path, char *arg, ...) | |
192 | { | |
193 | va_list ap, aq; | |
194 | unsigned i, length; | |
195 | char **args; | |
196 | ||
197 | __gcov_flush (); | |
198 | ||
199 | va_start (ap, arg); | |
200 | va_copy (aq, ap); | |
201 | ||
202 | length = 2; | |
203 | while (va_arg (ap, char *)) | |
204 | length++; | |
205 | va_end (ap); | |
206 | ||
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); | |
212 | ||
213 | return execv (path, args); | |
214 | } | |
215 | #endif | |
216 | ||
217 | #ifdef L_gcov_execlp | |
b98a872b NS |
218 | /* A wrapper for the execlp function. Flushes the accumulated |
219 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
220 | |
221 | int | |
222 | __gcov_execlp (const char *path, char *arg, ...) | |
223 | { | |
224 | va_list ap, aq; | |
225 | unsigned i, length; | |
226 | char **args; | |
227 | ||
228 | __gcov_flush (); | |
229 | ||
230 | va_start (ap, arg); | |
231 | va_copy (aq, ap); | |
232 | ||
233 | length = 2; | |
234 | while (va_arg (ap, char *)) | |
235 | length++; | |
236 | va_end (ap); | |
237 | ||
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); | |
243 | ||
244 | return execvp (path, args); | |
245 | } | |
246 | #endif | |
247 | ||
248 | #ifdef L_gcov_execle | |
b98a872b NS |
249 | /* A wrapper for the execle function. Flushes the accumulated |
250 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
251 | |
252 | int | |
253 | __gcov_execle (const char *path, char *arg, ...) | |
254 | { | |
255 | va_list ap, aq; | |
256 | unsigned i, length; | |
257 | char **args; | |
258 | char **envp; | |
259 | ||
260 | __gcov_flush (); | |
261 | ||
262 | va_start (ap, arg); | |
263 | va_copy (aq, ap); | |
264 | ||
265 | length = 2; | |
266 | while (va_arg (ap, char *)) | |
267 | length++; | |
268 | va_end (ap); | |
269 | ||
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); | |
276 | ||
277 | return execve (path, args, envp); | |
278 | } | |
279 | #endif | |
280 | ||
281 | #ifdef L_gcov_execv | |
b98a872b NS |
282 | /* A wrapper for the execv function. Flushes the accumulated |
283 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
284 | |
285 | int | |
286 | __gcov_execv (const char *path, char *const argv[]) | |
287 | { | |
288 | __gcov_flush (); | |
289 | return execv (path, argv); | |
290 | } | |
291 | #endif | |
292 | ||
293 | #ifdef L_gcov_execvp | |
b98a872b NS |
294 | /* A wrapper for the execvp function. Flushes the accumulated |
295 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
296 | |
297 | int | |
298 | __gcov_execvp (const char *path, char *const argv[]) | |
299 | { | |
300 | __gcov_flush (); | |
301 | return execvp (path, argv); | |
302 | } | |
303 | #endif | |
304 | ||
305 | #ifdef L_gcov_execve | |
b98a872b NS |
306 | /* A wrapper for the execve function. Flushes the accumulated |
307 | profiling data, so that they are not lost. */ | |
d6d3f033 RX |
308 | |
309 | int | |
310 | __gcov_execve (const char *path, char *const argv[], char *const envp[]) | |
311 | { | |
312 | __gcov_flush (); | |
313 | return execve (path, argv, envp); | |
314 | } | |
315 | #endif | |
316 | #endif /* inhibit_libc */ |