Mercurial > hg > CbC > CbC_gcc
comparison libgcc/libgcov-interface.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Routines required for instrumenting a program. */ | |
2 /* Compile this one with gcc. */ | |
3 /* Copyright (C) 1989-2017 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 /* Some functions we want to bind in this dynamic object, but have an | |
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 (); } | |
53 | |
54 extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; | |
55 extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; | |
56 | |
57 #ifdef L_gcov_flush | |
58 #ifdef __GTHREAD_MUTEX_INIT | |
59 __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; | |
60 #define init_mx_once() | |
61 #else | |
62 __gthread_mutex_t __gcov_flush_mx; | |
63 | |
64 static void | |
65 init_mx (void) | |
66 { | |
67 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); | |
68 } | |
69 | |
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 | |
88 __gcov_dump_int (); | |
89 __gcov_reset_int (); | |
90 | |
91 __gthread_mutex_unlock (&__gcov_flush_mx); | |
92 } | |
93 | |
94 #endif /* L_gcov_flush */ | |
95 | |
96 #ifdef L_gcov_reset | |
97 | |
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 | |
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 | |
133 __gcov_reset_int (void) | |
134 { | |
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 } | |
145 } | |
146 | |
147 ALIAS_void_fn (__gcov_reset_int, __gcov_reset); | |
148 | |
149 #endif /* L_gcov_reset */ | |
150 | |
151 #ifdef L_gcov_dump | |
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 | |
156 __gcov_dump_int (void) | |
157 { | |
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); | |
165 } | |
166 | |
167 ALIAS_void_fn (__gcov_dump_int, __gcov_dump); | |
168 | |
169 #endif /* L_gcov_dump */ | |
170 | |
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; | |
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 | |
188 /* A wrapper for the execl function. Flushes the accumulated | |
189 profiling data, so that they are not lost. */ | |
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 | |
219 /* A wrapper for the execlp function. Flushes the accumulated | |
220 profiling data, so that they are not lost. */ | |
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 | |
250 /* A wrapper for the execle function. Flushes the accumulated | |
251 profiling data, so that they are not lost. */ | |
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 | |
283 /* A wrapper for the execv function. Flushes the accumulated | |
284 profiling data, so that they are not lost. */ | |
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 | |
295 /* A wrapper for the execvp function. Flushes the accumulated | |
296 profiling data, so that they are not lost. */ | |
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 | |
307 /* A wrapper for the execve function. Flushes the accumulated | |
308 profiling data, so that they are not lost. */ | |
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 */ |