Mercurial > hg > CbC > CbC_gcc
annotate gcc/libgcov.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children | f6334be47118 |
rev | line source |
---|---|
0 | 1 /* Routines required for instrumenting a program. */ |
2 /* Compile this one with gcc. */ | |
3 /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | |
4 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 | |
5 Free Software Foundation, Inc. | |
6 | |
7 This file is part of GCC. | |
8 | |
9 GCC is free software; you can redistribute it and/or modify it under | |
10 the terms of the GNU General Public License as published by the Free | |
11 Software Foundation; either version 3, or (at your option) any later | |
12 version. | |
13 | |
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 Under Section 7 of GPL version 3, you are granted additional | |
20 permissions described in the GCC Runtime Library Exception, version | |
21 3.1, as published by the Free Software Foundation. | |
22 | |
23 You should have received a copy of the GNU General Public License and | |
24 a copy of the GCC Runtime Library Exception along with this program; | |
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
26 <http://www.gnu.org/licenses/>. */ | |
27 | |
28 #include "tconfig.h" | |
29 #include "tsystem.h" | |
30 #include "coretypes.h" | |
31 #include "tm.h" | |
32 | |
33 #if defined(inhibit_libc) | |
34 #define IN_LIBGCOV (-1) | |
35 #else | |
36 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ | |
37 #include <stdio.h> | |
38 #define IN_LIBGCOV 1 | |
39 #if defined(L_gcov) | |
40 #define GCOV_LINKAGE /* nothing */ | |
41 #endif | |
42 #endif | |
43 #include "gcov-io.h" | |
44 | |
45 #if defined(inhibit_libc) | |
46 /* If libc and its header files are not available, provide dummy functions. */ | |
47 | |
48 #ifdef L_gcov | |
49 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} | |
50 void __gcov_flush (void) {} | |
51 #endif | |
52 | |
53 #ifdef L_gcov_merge_add | |
54 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), | |
55 unsigned n_counters __attribute__ ((unused))) {} | |
56 #endif | |
57 | |
58 #ifdef L_gcov_merge_single | |
59 void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), | |
60 unsigned n_counters __attribute__ ((unused))) {} | |
61 #endif | |
62 | |
63 #ifdef L_gcov_merge_delta | |
64 void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)), | |
65 unsigned n_counters __attribute__ ((unused))) {} | |
66 #endif | |
67 | |
68 #else | |
69 | |
70 #include <string.h> | |
71 #if GCOV_LOCKED | |
72 #include <fcntl.h> | |
73 #include <errno.h> | |
74 #include <sys/stat.h> | |
75 #endif | |
76 | |
77 #ifdef L_gcov | |
78 #include "gcov-io.c" | |
79 | |
80 /* Chain of per-object gcov structures. */ | |
81 static struct gcov_info *gcov_list; | |
82 | |
83 /* A program checksum allows us to distinguish program data for an | |
84 object file included in multiple programs. */ | |
85 static gcov_unsigned_t gcov_crc32; | |
86 | |
87 /* Size of the longest file name. */ | |
88 static size_t gcov_max_filename = 0; | |
89 | |
90 #ifdef TARGET_POSIX_IO | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
91 /* Make sure path component of the given FILENAME exists, create |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
92 missing directories. FILENAME must be writable. |
0 | 93 Returns zero on success, or -1 if an error occurred. */ |
94 | |
95 static int | |
96 create_file_directory (char *filename) | |
97 { | |
98 char *s; | |
99 | |
100 for (s = filename + 1; *s != '\0'; s++) | |
101 if (IS_DIR_SEPARATOR(*s)) | |
102 { | |
103 char sep = *s; | |
104 *s = '\0'; | |
105 | |
106 /* Try to make directory if it doesn't already exist. */ | |
107 if (access (filename, F_OK) == -1 | |
108 && mkdir (filename, 0755) == -1 | |
109 /* The directory might have been made by another process. */ | |
110 && errno != EEXIST) | |
111 { | |
112 fprintf (stderr, "profiling:%s:Cannot create directory\n", | |
113 filename); | |
114 *s = sep; | |
115 return -1; | |
116 }; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
117 |
0 | 118 *s = sep; |
119 }; | |
120 return 0; | |
121 } | |
122 #endif | |
123 | |
124 /* Check if VERSION of the info block PTR matches libgcov one. | |
125 Return 1 on success, or zero in case of versions mismatch. | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
126 If FILENAME is not NULL, its value used for reporting purposes |
0 | 127 instead of value from the info block. */ |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
128 |
0 | 129 static int |
130 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, | |
131 const char *filename) | |
132 { | |
133 if (version != GCOV_VERSION) | |
134 { | |
135 char v[4], e[4]; | |
136 | |
137 GCOV_UNSIGNED2STRING (v, version); | |
138 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
139 |
0 | 140 fprintf (stderr, |
141 "profiling:%s:Version mismatch - expected %.4s got %.4s\n", | |
142 filename? filename : ptr->filename, e, v); | |
143 return 0; | |
144 } | |
145 return 1; | |
146 } | |
147 | |
148 /* Dump the coverage counts. We merge with existing counts when | |
149 possible, to avoid growing the .da files ad infinitum. We use this | |
150 program's checksum to make sure we only accumulate whole program | |
151 statistics to the correct summary. An object file might be embedded | |
152 in two separate programs, and we must keep the two program | |
153 summaries separate. */ | |
154 | |
155 static void | |
156 gcov_exit (void) | |
157 { | |
158 struct gcov_info *gi_ptr; | |
159 struct gcov_summary this_program; | |
160 struct gcov_summary all; | |
161 struct gcov_ctr_summary *cs_ptr; | |
162 const struct gcov_ctr_info *ci_ptr; | |
163 unsigned t_ix; | |
164 gcov_unsigned_t c_num; | |
165 const char *gcov_prefix; | |
166 int gcov_prefix_strip = 0; | |
167 size_t prefix_length; | |
168 char *gi_filename, *gi_filename_up; | |
169 | |
170 memset (&all, 0, sizeof (all)); | |
171 /* Find the totals for this execution. */ | |
172 memset (&this_program, 0, sizeof (this_program)); | |
173 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | |
174 { | |
175 ci_ptr = gi_ptr->counts; | |
176 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) | |
177 { | |
178 if (!((1 << t_ix) & gi_ptr->ctr_mask)) | |
179 continue; | |
180 | |
181 cs_ptr = &this_program.ctrs[t_ix]; | |
182 cs_ptr->num += ci_ptr->num; | |
183 for (c_num = 0; c_num < ci_ptr->num; c_num++) | |
184 { | |
185 cs_ptr->sum_all += ci_ptr->values[c_num]; | |
186 if (cs_ptr->run_max < ci_ptr->values[c_num]) | |
187 cs_ptr->run_max = ci_ptr->values[c_num]; | |
188 } | |
189 ci_ptr++; | |
190 } | |
191 } | |
192 | |
193 /* Get file name relocation prefix. Non-absolute values are ignored. */ | |
194 gcov_prefix = getenv("GCOV_PREFIX"); | |
195 if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix)) | |
196 { | |
197 /* Check if the level of dirs to strip off specified. */ | |
198 char *tmp = getenv("GCOV_PREFIX_STRIP"); | |
199 if (tmp) | |
200 { | |
201 gcov_prefix_strip = atoi (tmp); | |
202 /* Do not consider negative values. */ | |
203 if (gcov_prefix_strip < 0) | |
204 gcov_prefix_strip = 0; | |
205 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
206 |
0 | 207 prefix_length = strlen(gcov_prefix); |
208 | |
209 /* Remove an unnecessary trailing '/' */ | |
210 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) | |
211 prefix_length--; | |
212 } | |
213 else | |
214 prefix_length = 0; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
215 |
0 | 216 /* Allocate and initialize the filename scratch space. */ |
217 gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1); | |
218 if (prefix_length) | |
219 memcpy (gi_filename, gcov_prefix, prefix_length); | |
220 gi_filename_up = gi_filename + prefix_length; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
221 |
0 | 222 /* Now merge each file. */ |
223 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | |
224 { | |
225 struct gcov_summary this_object; | |
226 struct gcov_summary object, program; | |
227 gcov_type *values[GCOV_COUNTERS]; | |
228 const struct gcov_fn_info *fi_ptr; | |
229 unsigned fi_stride; | |
230 unsigned c_ix, f_ix, n_counts; | |
231 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; | |
232 int error = 0; | |
233 gcov_unsigned_t tag, length; | |
234 gcov_position_t summary_pos = 0; | |
235 gcov_position_t eof_pos = 0; | |
236 | |
237 memset (&this_object, 0, sizeof (this_object)); | |
238 memset (&object, 0, sizeof (object)); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
239 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
240 /* Build relocated filename, stripping off leading |
0 | 241 directories from the initial filename if requested. */ |
242 if (gcov_prefix_strip > 0) | |
243 { | |
244 int level = 0; | |
245 const char *fname = gi_ptr->filename; | |
246 const char *s; | |
247 | |
248 /* Skip selected directory levels. */ | |
249 for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++) | |
250 if (IS_DIR_SEPARATOR(*s)) | |
251 { | |
252 fname = s; | |
253 level++; | |
254 }; | |
255 | |
256 /* Update complete filename with stripped original. */ | |
257 strcpy (gi_filename_up, fname); | |
258 } | |
259 else | |
260 strcpy (gi_filename_up, gi_ptr->filename); | |
261 | |
262 /* Totals for this object file. */ | |
263 ci_ptr = gi_ptr->counts; | |
264 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) | |
265 { | |
266 if (!((1 << t_ix) & gi_ptr->ctr_mask)) | |
267 continue; | |
268 | |
269 cs_ptr = &this_object.ctrs[t_ix]; | |
270 cs_ptr->num += ci_ptr->num; | |
271 for (c_num = 0; c_num < ci_ptr->num; c_num++) | |
272 { | |
273 cs_ptr->sum_all += ci_ptr->values[c_num]; | |
274 if (cs_ptr->run_max < ci_ptr->values[c_num]) | |
275 cs_ptr->run_max = ci_ptr->values[c_num]; | |
276 } | |
277 | |
278 ci_ptr++; | |
279 } | |
280 | |
281 c_ix = 0; | |
282 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | |
283 if ((1 << t_ix) & gi_ptr->ctr_mask) | |
284 { | |
285 values[c_ix] = gi_ptr->counts[c_ix].values; | |
286 c_ix++; | |
287 } | |
288 | |
289 /* Calculate the function_info stride. This depends on the | |
290 number of counter types being measured. */ | |
291 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned); | |
292 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) | |
293 { | |
294 fi_stride += __alignof__ (struct gcov_fn_info) - 1; | |
295 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); | |
296 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
297 |
0 | 298 if (!gcov_open (gi_filename)) |
299 { | |
300 #ifdef TARGET_POSIX_IO | |
301 /* Open failed likely due to missed directory. | |
302 Create directory and retry to open file. */ | |
303 if (create_file_directory (gi_filename)) | |
304 { | |
305 fprintf (stderr, "profiling:%s:Skip\n", gi_filename); | |
306 continue; | |
307 } | |
308 #endif | |
309 if (!gcov_open (gi_filename)) | |
310 { | |
311 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename); | |
312 continue; | |
313 } | |
314 } | |
315 | |
316 tag = gcov_read_unsigned (); | |
317 if (tag) | |
318 { | |
319 /* Merge data from file. */ | |
320 if (tag != GCOV_DATA_MAGIC) | |
321 { | |
322 fprintf (stderr, "profiling:%s:Not a gcov data file\n", | |
323 gi_filename); | |
324 goto read_fatal; | |
325 } | |
326 length = gcov_read_unsigned (); | |
327 if (!gcov_version (gi_ptr, length, gi_filename)) | |
328 goto read_fatal; | |
329 | |
330 length = gcov_read_unsigned (); | |
331 if (length != gi_ptr->stamp) | |
332 /* Read from a different compilation. Overwrite the file. */ | |
333 goto rewrite; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
334 |
0 | 335 /* Merge execution counts for each function. */ |
336 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) | |
337 { | |
338 fi_ptr = (const struct gcov_fn_info *) | |
339 ((const char *) gi_ptr->functions + f_ix * fi_stride); | |
340 tag = gcov_read_unsigned (); | |
341 length = gcov_read_unsigned (); | |
342 | |
343 /* Check function. */ | |
344 if (tag != GCOV_TAG_FUNCTION | |
345 || length != GCOV_TAG_FUNCTION_LENGTH | |
346 || gcov_read_unsigned () != fi_ptr->ident | |
347 || gcov_read_unsigned () != fi_ptr->checksum) | |
348 { | |
349 read_mismatch:; | |
350 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", | |
351 gi_filename, | |
352 f_ix + 1 ? "function" : "summaries"); | |
353 goto read_fatal; | |
354 } | |
355 | |
356 c_ix = 0; | |
357 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | |
358 { | |
359 gcov_merge_fn merge; | |
360 | |
361 if (!((1 << t_ix) & gi_ptr->ctr_mask)) | |
362 continue; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
363 |
0 | 364 n_counts = fi_ptr->n_ctrs[c_ix]; |
365 merge = gi_ptr->counts[c_ix].merge; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
366 |
0 | 367 tag = gcov_read_unsigned (); |
368 length = gcov_read_unsigned (); | |
369 if (tag != GCOV_TAG_FOR_COUNTER (t_ix) | |
370 || length != GCOV_TAG_COUNTER_LENGTH (n_counts)) | |
371 goto read_mismatch; | |
372 (*merge) (values[c_ix], n_counts); | |
373 values[c_ix] += n_counts; | |
374 c_ix++; | |
375 } | |
376 if ((error = gcov_is_error ())) | |
377 goto read_error; | |
378 } | |
379 | |
380 f_ix = ~0u; | |
381 /* Check program & object summary */ | |
382 while (1) | |
383 { | |
384 int is_program; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
385 |
0 | 386 eof_pos = gcov_position (); |
387 tag = gcov_read_unsigned (); | |
388 if (!tag) | |
389 break; | |
390 | |
391 length = gcov_read_unsigned (); | |
392 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; | |
393 if (length != GCOV_TAG_SUMMARY_LENGTH | |
394 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY)) | |
395 goto read_mismatch; | |
396 gcov_read_summary (is_program ? &program : &object); | |
397 if ((error = gcov_is_error ())) | |
398 goto read_error; | |
399 if (is_program && program.checksum == gcov_crc32) | |
400 { | |
401 summary_pos = eof_pos; | |
402 goto rewrite; | |
403 } | |
404 } | |
405 } | |
406 goto rewrite; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
407 |
0 | 408 read_error:; |
409 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" | |
410 : "profiling:%s:Error merging\n", gi_filename); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
411 |
0 | 412 read_fatal:; |
413 gcov_close (); | |
414 continue; | |
415 | |
416 rewrite:; | |
417 gcov_rewrite (); | |
418 if (!summary_pos) | |
419 memset (&program, 0, sizeof (program)); | |
420 | |
421 /* Merge the summaries. */ | |
422 f_ix = ~0u; | |
423 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) | |
424 { | |
425 cs_obj = &object.ctrs[t_ix]; | |
426 cs_tobj = &this_object.ctrs[t_ix]; | |
427 cs_prg = &program.ctrs[t_ix]; | |
428 cs_tprg = &this_program.ctrs[t_ix]; | |
429 cs_all = &all.ctrs[t_ix]; | |
430 | |
431 if ((1 << t_ix) & gi_ptr->ctr_mask) | |
432 { | |
433 if (!cs_obj->runs++) | |
434 cs_obj->num = cs_tobj->num; | |
435 else if (cs_obj->num != cs_tobj->num) | |
436 goto read_mismatch; | |
437 cs_obj->sum_all += cs_tobj->sum_all; | |
438 if (cs_obj->run_max < cs_tobj->run_max) | |
439 cs_obj->run_max = cs_tobj->run_max; | |
440 cs_obj->sum_max += cs_tobj->run_max; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
441 |
0 | 442 if (!cs_prg->runs++) |
443 cs_prg->num = cs_tprg->num; | |
444 else if (cs_prg->num != cs_tprg->num) | |
445 goto read_mismatch; | |
446 cs_prg->sum_all += cs_tprg->sum_all; | |
447 if (cs_prg->run_max < cs_tprg->run_max) | |
448 cs_prg->run_max = cs_tprg->run_max; | |
449 cs_prg->sum_max += cs_tprg->run_max; | |
450 } | |
451 else if (cs_obj->num || cs_prg->num) | |
452 goto read_mismatch; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
453 |
0 | 454 if (!cs_all->runs && cs_prg->runs) |
455 memcpy (cs_all, cs_prg, sizeof (*cs_all)); | |
456 else if (!all.checksum | |
457 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs) | |
458 && memcmp (cs_all, cs_prg, sizeof (*cs_all))) | |
459 { | |
460 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", | |
461 gi_filename, GCOV_LOCKED | |
462 ? "" : " or concurrent update without locking support"); | |
463 all.checksum = ~0u; | |
464 } | |
465 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
466 |
0 | 467 c_ix = 0; |
468 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | |
469 if ((1 << t_ix) & gi_ptr->ctr_mask) | |
470 { | |
471 values[c_ix] = gi_ptr->counts[c_ix].values; | |
472 c_ix++; | |
473 } | |
474 | |
475 program.checksum = gcov_crc32; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
476 |
0 | 477 /* Write out the data. */ |
478 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); | |
479 gcov_write_unsigned (gi_ptr->stamp); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
480 |
0 | 481 /* Write execution counts for each function. */ |
482 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) | |
483 { | |
484 fi_ptr = (const struct gcov_fn_info *) | |
485 ((const char *) gi_ptr->functions + f_ix * fi_stride); | |
486 | |
487 /* Announce function. */ | |
488 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH); | |
489 gcov_write_unsigned (fi_ptr->ident); | |
490 gcov_write_unsigned (fi_ptr->checksum); | |
491 | |
492 c_ix = 0; | |
493 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) | |
494 { | |
495 gcov_type *c_ptr; | |
496 | |
497 if (!((1 << t_ix) & gi_ptr->ctr_mask)) | |
498 continue; | |
499 | |
500 n_counts = fi_ptr->n_ctrs[c_ix]; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
501 |
0 | 502 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), |
503 GCOV_TAG_COUNTER_LENGTH (n_counts)); | |
504 c_ptr = values[c_ix]; | |
505 while (n_counts--) | |
506 gcov_write_counter (*c_ptr++); | |
507 | |
508 values[c_ix] = c_ptr; | |
509 c_ix++; | |
510 } | |
511 } | |
512 | |
513 /* Object file summary. */ | |
514 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); | |
515 | |
516 /* Generate whole program statistics. */ | |
517 if (eof_pos) | |
518 gcov_seek (eof_pos); | |
519 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program); | |
520 if (!summary_pos) | |
521 gcov_write_unsigned (0); | |
522 if ((error = gcov_close ())) | |
523 fprintf (stderr, error < 0 ? | |
524 "profiling:%s:Overflow writing\n" : | |
525 "profiling:%s:Error writing\n", | |
526 gi_filename); | |
527 } | |
528 } | |
529 | |
530 /* Add a new object file onto the bb chain. Invoked automatically | |
531 when running an object file's global ctors. */ | |
532 | |
533 void | |
534 __gcov_init (struct gcov_info *info) | |
535 { | |
536 if (!info->version) | |
537 return; | |
538 if (gcov_version (info, info->version, 0)) | |
539 { | |
540 const char *ptr = info->filename; | |
541 gcov_unsigned_t crc32 = gcov_crc32; | |
542 size_t filename_length = strlen(info->filename); | |
543 | |
544 /* Refresh the longest file name information */ | |
545 if (filename_length > gcov_max_filename) | |
546 gcov_max_filename = filename_length; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
547 |
0 | 548 do |
549 { | |
550 unsigned ix; | |
551 gcov_unsigned_t value = *ptr << 24; | |
552 | |
553 for (ix = 8; ix--; value <<= 1) | |
554 { | |
555 gcov_unsigned_t feedback; | |
556 | |
557 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; | |
558 crc32 <<= 1; | |
559 crc32 ^= feedback; | |
560 } | |
561 } | |
562 while (*ptr++); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
563 |
0 | 564 gcov_crc32 = crc32; |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
565 |
0 | 566 if (!gcov_list) |
567 atexit (gcov_exit); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
568 |
0 | 569 info->next = gcov_list; |
570 gcov_list = info; | |
571 } | |
572 info->version = 0; | |
573 } | |
574 | |
575 /* Called before fork or exec - write out profile information gathered so | |
576 far and reset it to zero. This avoids duplication or loss of the | |
577 profile information gathered so far. */ | |
578 | |
579 void | |
580 __gcov_flush (void) | |
581 { | |
582 const struct gcov_info *gi_ptr; | |
583 | |
584 gcov_exit (); | |
585 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | |
586 { | |
587 unsigned t_ix; | |
588 const struct gcov_ctr_info *ci_ptr; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
589 |
0 | 590 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++) |
591 if ((1 << t_ix) & gi_ptr->ctr_mask) | |
592 { | |
593 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); | |
594 ci_ptr++; | |
595 } | |
596 } | |
597 } | |
598 | |
599 #endif /* L_gcov */ | |
600 | |
601 #ifdef L_gcov_merge_add | |
602 /* The profile merging function that just adds the counters. It is given | |
603 an array COUNTERS of N_COUNTERS old counters and it reads the same number | |
604 of counters from the gcov file. */ | |
605 void | |
606 __gcov_merge_add (gcov_type *counters, unsigned n_counters) | |
607 { | |
608 for (; n_counters; counters++, n_counters--) | |
609 *counters += gcov_read_counter (); | |
610 } | |
611 #endif /* L_gcov_merge_add */ | |
612 | |
613 #ifdef L_gcov_merge_ior | |
614 /* The profile merging function that just adds the counters. It is given | |
615 an array COUNTERS of N_COUNTERS old counters and it reads the same number | |
616 of counters from the gcov file. */ | |
617 void | |
618 __gcov_merge_ior (gcov_type *counters, unsigned n_counters) | |
619 { | |
620 for (; n_counters; counters++, n_counters--) | |
621 *counters |= gcov_read_counter (); | |
622 } | |
623 #endif | |
624 | |
625 #ifdef L_gcov_merge_single | |
626 /* The profile merging function for choosing the most common value. | |
627 It is given an array COUNTERS of N_COUNTERS old counters and it | |
628 reads the same number of counters from the gcov file. The counters | |
629 are split into 3-tuples where the members of the tuple have | |
630 meanings: | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
631 |
0 | 632 -- the stored candidate on the most common value of the measured entity |
633 -- counter | |
634 -- total number of evaluations of the value */ | |
635 void | |
636 __gcov_merge_single (gcov_type *counters, unsigned n_counters) | |
637 { | |
638 unsigned i, n_measures; | |
639 gcov_type value, counter, all; | |
640 | |
641 gcc_assert (!(n_counters % 3)); | |
642 n_measures = n_counters / 3; | |
643 for (i = 0; i < n_measures; i++, counters += 3) | |
644 { | |
645 value = gcov_read_counter (); | |
646 counter = gcov_read_counter (); | |
647 all = gcov_read_counter (); | |
648 | |
649 if (counters[0] == value) | |
650 counters[1] += counter; | |
651 else if (counter > counters[1]) | |
652 { | |
653 counters[0] = value; | |
654 counters[1] = counter - counters[1]; | |
655 } | |
656 else | |
657 counters[1] -= counter; | |
658 counters[2] += all; | |
659 } | |
660 } | |
661 #endif /* L_gcov_merge_single */ | |
662 | |
663 #ifdef L_gcov_merge_delta | |
664 /* The profile merging function for choosing the most common | |
665 difference between two consecutive evaluations of the value. It is | |
666 given an array COUNTERS of N_COUNTERS old counters and it reads the | |
667 same number of counters from the gcov file. The counters are split | |
668 into 4-tuples where the members of the tuple have meanings: | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
669 |
0 | 670 -- the last value of the measured entity |
671 -- the stored candidate on the most common difference | |
672 -- counter | |
673 -- total number of evaluations of the value */ | |
674 void | |
675 __gcov_merge_delta (gcov_type *counters, unsigned n_counters) | |
676 { | |
677 unsigned i, n_measures; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
678 gcov_type value, counter, all; |
0 | 679 |
680 gcc_assert (!(n_counters % 4)); | |
681 n_measures = n_counters / 4; | |
682 for (i = 0; i < n_measures; i++, counters += 4) | |
683 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
684 /* last = */ gcov_read_counter (); |
0 | 685 value = gcov_read_counter (); |
686 counter = gcov_read_counter (); | |
687 all = gcov_read_counter (); | |
688 | |
689 if (counters[1] == value) | |
690 counters[2] += counter; | |
691 else if (counter > counters[2]) | |
692 { | |
693 counters[1] = value; | |
694 counters[2] = counter - counters[2]; | |
695 } | |
696 else | |
697 counters[2] -= counter; | |
698 counters[3] += all; | |
699 } | |
700 } | |
701 #endif /* L_gcov_merge_delta */ | |
702 | |
703 #ifdef L_gcov_interval_profiler | |
704 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the | |
705 corresponding counter in COUNTERS. If the VALUE is above or below | |
706 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased | |
707 instead. */ | |
708 | |
709 void | |
710 __gcov_interval_profiler (gcov_type *counters, gcov_type value, | |
711 int start, unsigned steps) | |
712 { | |
713 gcov_type delta = value - start; | |
714 if (delta < 0) | |
715 counters[steps + 1]++; | |
716 else if (delta >= steps) | |
717 counters[steps]++; | |
718 else | |
719 counters[delta]++; | |
720 } | |
721 #endif | |
722 | |
723 #ifdef L_gcov_pow2_profiler | |
724 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise | |
725 COUNTERS[0] is incremented. */ | |
726 | |
727 void | |
728 __gcov_pow2_profiler (gcov_type *counters, gcov_type value) | |
729 { | |
730 if (value & (value - 1)) | |
731 counters[0]++; | |
732 else | |
733 counters[1]++; | |
734 } | |
735 #endif | |
736 | |
737 /* Tries to determine the most common value among its inputs. Checks if the | |
738 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] | |
739 is incremented. If this is not the case and COUNTERS[1] is not zero, | |
740 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and | |
741 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this | |
742 function is called more than 50% of the time with one value, this value | |
743 will be in COUNTERS[0] in the end. | |
744 | |
745 In any case, COUNTERS[2] is incremented. */ | |
746 | |
747 static inline void | |
748 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) | |
749 { | |
750 if (value == counters[0]) | |
751 counters[1]++; | |
752 else if (counters[1] == 0) | |
753 { | |
754 counters[1] = 1; | |
755 counters[0] = value; | |
756 } | |
757 else | |
758 counters[1]--; | |
759 counters[2]++; | |
760 } | |
761 | |
762 #ifdef L_gcov_one_value_profiler | |
763 void | |
764 __gcov_one_value_profiler (gcov_type *counters, gcov_type value) | |
765 { | |
766 __gcov_one_value_profiler_body (counters, value); | |
767 } | |
768 #endif | |
769 | |
770 #ifdef L_gcov_indirect_call_profiler | |
771 /* Tries to determine the most common value among its inputs. */ | |
772 void | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
773 __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value, |
0 | 774 void* cur_func, void* callee_func) |
775 { | |
776 /* If the C++ virtual tables contain function descriptors then one | |
777 function may have multiple descriptors and we need to dereference | |
778 the descriptors to see if they point to the same function. */ | |
779 if (cur_func == callee_func | |
780 || (TARGET_VTABLE_USES_DESCRIPTORS && callee_func | |
781 && *(void **) cur_func == *(void **) callee_func)) | |
782 __gcov_one_value_profiler_body (counter, value); | |
783 } | |
784 #endif | |
785 | |
786 | |
787 #ifdef L_gcov_average_profiler | |
788 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want | |
789 to saturate up. */ | |
790 | |
791 void | |
792 __gcov_average_profiler (gcov_type *counters, gcov_type value) | |
793 { | |
794 counters[0] += value; | |
795 counters[1] ++; | |
796 } | |
797 #endif | |
798 | |
799 #ifdef L_gcov_ior_profiler | |
800 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want | |
801 to saturate up. */ | |
802 | |
803 void | |
804 __gcov_ior_profiler (gcov_type *counters, gcov_type value) | |
805 { | |
806 *counters |= value; | |
807 } | |
808 #endif | |
809 | |
810 #ifdef L_gcov_fork | |
811 /* A wrapper for the fork function. Flushes the accumulated profiling data, so | |
812 that they are not counted twice. */ | |
813 | |
814 pid_t | |
815 __gcov_fork (void) | |
816 { | |
817 __gcov_flush (); | |
818 return fork (); | |
819 } | |
820 #endif | |
821 | |
822 #ifdef L_gcov_execl | |
823 /* A wrapper for the execl function. Flushes the accumulated profiling data, so | |
824 that they are not lost. */ | |
825 | |
826 int | |
827 __gcov_execl (const char *path, char *arg, ...) | |
828 { | |
829 va_list ap, aq; | |
830 unsigned i, length; | |
831 char **args; | |
832 | |
833 __gcov_flush (); | |
834 | |
835 va_start (ap, arg); | |
836 va_copy (aq, ap); | |
837 | |
838 length = 2; | |
839 while (va_arg (ap, char *)) | |
840 length++; | |
841 va_end (ap); | |
842 | |
843 args = (char **) alloca (length * sizeof (void *)); | |
844 args[0] = arg; | |
845 for (i = 1; i < length; i++) | |
846 args[i] = va_arg (aq, char *); | |
847 va_end (aq); | |
848 | |
849 return execv (path, args); | |
850 } | |
851 #endif | |
852 | |
853 #ifdef L_gcov_execlp | |
854 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so | |
855 that they are not lost. */ | |
856 | |
857 int | |
858 __gcov_execlp (const char *path, char *arg, ...) | |
859 { | |
860 va_list ap, aq; | |
861 unsigned i, length; | |
862 char **args; | |
863 | |
864 __gcov_flush (); | |
865 | |
866 va_start (ap, arg); | |
867 va_copy (aq, ap); | |
868 | |
869 length = 2; | |
870 while (va_arg (ap, char *)) | |
871 length++; | |
872 va_end (ap); | |
873 | |
874 args = (char **) alloca (length * sizeof (void *)); | |
875 args[0] = arg; | |
876 for (i = 1; i < length; i++) | |
877 args[i] = va_arg (aq, char *); | |
878 va_end (aq); | |
879 | |
880 return execvp (path, args); | |
881 } | |
882 #endif | |
883 | |
884 #ifdef L_gcov_execle | |
885 /* A wrapper for the execle function. Flushes the accumulated profiling data, so | |
886 that they are not lost. */ | |
887 | |
888 int | |
889 __gcov_execle (const char *path, char *arg, ...) | |
890 { | |
891 va_list ap, aq; | |
892 unsigned i, length; | |
893 char **args; | |
894 char **envp; | |
895 | |
896 __gcov_flush (); | |
897 | |
898 va_start (ap, arg); | |
899 va_copy (aq, ap); | |
900 | |
901 length = 2; | |
902 while (va_arg (ap, char *)) | |
903 length++; | |
904 va_end (ap); | |
905 | |
906 args = (char **) alloca (length * sizeof (void *)); | |
907 args[0] = arg; | |
908 for (i = 1; i < length; i++) | |
909 args[i] = va_arg (aq, char *); | |
910 envp = va_arg (aq, char **); | |
911 va_end (aq); | |
912 | |
913 return execve (path, args, envp); | |
914 } | |
915 #endif | |
916 | |
917 #ifdef L_gcov_execv | |
918 /* A wrapper for the execv function. Flushes the accumulated profiling data, so | |
919 that they are not lost. */ | |
920 | |
921 int | |
922 __gcov_execv (const char *path, char *const argv[]) | |
923 { | |
924 __gcov_flush (); | |
925 return execv (path, argv); | |
926 } | |
927 #endif | |
928 | |
929 #ifdef L_gcov_execvp | |
930 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so | |
931 that they are not lost. */ | |
932 | |
933 int | |
934 __gcov_execvp (const char *path, char *const argv[]) | |
935 { | |
936 __gcov_flush (); | |
937 return execvp (path, argv); | |
938 } | |
939 #endif | |
940 | |
941 #ifdef L_gcov_execve | |
942 /* A wrapper for the execve function. Flushes the accumulated profiling data, so | |
943 that they are not lost. */ | |
944 | |
945 int | |
946 __gcov_execve (const char *path, char *const argv[], char *const envp[]) | |
947 { | |
948 __gcov_flush (); | |
949 return execve (path, argv, envp); | |
950 } | |
951 #endif | |
952 #endif /* inhibit_libc */ |