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