2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / libgcov.c
blobffc3d54752c5006ee5257bb5fa6130d01c5a21a4
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 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
22 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23 WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 for more details.
27 You should have received a copy of the GNU General Public License
28 along with GCC; see the file COPYING. If not, write to the Free
29 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
30 02111-1307, USA. */
32 /* It is incorrect to include config.h here, because this file is being
33 compiled for the target, and hence definitions concerning only the host
34 do not apply. */
36 #include "tconfig.h"
37 #include "tsystem.h"
38 #include "coretypes.h"
39 #include "tm.h"
41 #if defined(inhibit_libc)
42 #define IN_LIBGCOV (-1)
43 #else
44 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
45 #include <stdio.h>
46 #define IN_LIBGCOV 1
47 #if defined(L_gcov)
48 #define GCOV_LINKAGE /* nothing */
49 #endif
50 #endif
51 #include "gcov-io.h"
53 #if defined(inhibit_libc)
54 /* If libc and its header files are not available, provide dummy functions. */
56 #ifdef L_gcov
57 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
58 void __gcov_flush (void) {}
59 #endif
61 #ifdef L_gcov_merge_add
62 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
63 unsigned n_counters __attribute__ ((unused))) {}
64 #endif
66 #ifdef L_gcov_merge_single
67 void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
68 unsigned n_counters __attribute__ ((unused))) {}
69 #endif
71 #ifdef L_gcov_merge_delta
72 void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
73 unsigned n_counters __attribute__ ((unused))) {}
74 #endif
76 #else
78 #include <string.h>
79 #if GCOV_LOCKED
80 #include <fcntl.h>
81 #include <errno.h>
82 #endif
84 #ifdef L_gcov
85 #include "gcov-io.c"
87 /* Chain of per-object gcov structures. */
88 static struct gcov_info *gcov_list;
90 /* A program checksum allows us to distinguish program data for an
91 object file included in multiple programs. */
92 static gcov_unsigned_t gcov_crc32;
94 static int
95 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
97 if (version != GCOV_VERSION)
99 char v[4], e[4];
101 GCOV_UNSIGNED2STRING (v, version);
102 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
104 fprintf (stderr,
105 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
106 ptr->filename, e, v);
107 return 0;
109 return 1;
112 /* Dump the coverage counts. We merge with existing counts when
113 possible, to avoid growing the .da files ad infinitum. We use this
114 program's checksum to make sure we only accumulate whole program
115 statistics to the correct summary. An object file might be embedded
116 in two separate programs, and we must keep the two program
117 summaries separate. */
119 static void
120 gcov_exit (void)
122 struct gcov_info *gi_ptr;
123 struct gcov_summary this_program;
124 struct gcov_summary all;
125 struct gcov_ctr_summary *cs_ptr;
126 const struct gcov_ctr_info *ci_ptr;
127 unsigned t_ix;
128 gcov_unsigned_t c_num;
130 memset (&all, 0, sizeof (all));
131 /* Find the totals for this execution. */
132 memset (&this_program, 0, sizeof (this_program));
133 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
135 ci_ptr = gi_ptr->counts;
136 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
138 if (!((1 << t_ix) & gi_ptr->ctr_mask))
139 continue;
141 cs_ptr = &this_program.ctrs[t_ix];
142 cs_ptr->num += ci_ptr->num;
143 for (c_num = 0; c_num < ci_ptr->num; c_num++)
145 cs_ptr->sum_all += ci_ptr->values[c_num];
146 if (cs_ptr->run_max < ci_ptr->values[c_num])
147 cs_ptr->run_max = ci_ptr->values[c_num];
149 ci_ptr++;
153 /* Now merge each file. */
154 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
156 struct gcov_summary this_object;
157 struct gcov_summary object, program;
158 gcov_type *values[GCOV_COUNTERS];
159 const struct gcov_fn_info *fi_ptr;
160 unsigned fi_stride;
161 unsigned c_ix, f_ix, n_counts;
162 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
163 int error = 0;
164 gcov_unsigned_t tag, length;
165 gcov_position_t summary_pos = 0;
167 memset (&this_object, 0, sizeof (this_object));
168 memset (&object, 0, sizeof (object));
170 /* Totals for this object file. */
171 ci_ptr = gi_ptr->counts;
172 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
174 if (!((1 << t_ix) & gi_ptr->ctr_mask))
175 continue;
177 cs_ptr = &this_object.ctrs[t_ix];
178 cs_ptr->num += ci_ptr->num;
179 for (c_num = 0; c_num < ci_ptr->num; c_num++)
181 cs_ptr->sum_all += ci_ptr->values[c_num];
182 if (cs_ptr->run_max < ci_ptr->values[c_num])
183 cs_ptr->run_max = ci_ptr->values[c_num];
186 ci_ptr++;
189 c_ix = 0;
190 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
191 if ((1 << t_ix) & gi_ptr->ctr_mask)
193 values[c_ix] = gi_ptr->counts[c_ix].values;
194 c_ix++;
197 /* Calculate the function_info stride. This depends on the
198 number of counter types being measured. */
199 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
200 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
202 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
203 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
206 if (!gcov_open (gi_ptr->filename))
208 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
209 continue;
212 tag = gcov_read_unsigned ();
213 if (tag)
215 /* Merge data from file. */
216 if (tag != GCOV_DATA_MAGIC)
218 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
219 gi_ptr->filename);
220 read_fatal:;
221 gcov_close ();
222 continue;
224 length = gcov_read_unsigned ();
225 if (!gcov_version (gi_ptr, length))
226 goto read_fatal;
228 length = gcov_read_unsigned ();
229 if (length != gi_ptr->stamp)
231 /* Read from a different compilation. Overwrite the
232 file. */
233 gcov_truncate ();
234 goto rewrite;
237 /* Merge execution counts for each function. */
238 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
240 fi_ptr = (const struct gcov_fn_info *)
241 ((const char *) gi_ptr->functions + f_ix * fi_stride);
242 tag = gcov_read_unsigned ();
243 length = gcov_read_unsigned ();
245 /* Check function. */
246 if (tag != GCOV_TAG_FUNCTION
247 || length != GCOV_TAG_FUNCTION_LENGTH
248 || gcov_read_unsigned () != fi_ptr->ident
249 || gcov_read_unsigned () != fi_ptr->checksum)
251 read_mismatch:;
252 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
253 gi_ptr->filename,
254 f_ix + 1 ? "function" : "summaries");
255 goto read_fatal;
258 c_ix = 0;
259 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
261 gcov_merge_fn merge;
263 if (!((1 << t_ix) & gi_ptr->ctr_mask))
264 continue;
266 n_counts = fi_ptr->n_ctrs[c_ix];
267 merge = gi_ptr->counts[c_ix].merge;
269 tag = gcov_read_unsigned ();
270 length = gcov_read_unsigned ();
271 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
272 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
273 goto read_mismatch;
274 (*merge) (values[c_ix], n_counts);
275 values[c_ix] += n_counts;
276 c_ix++;
278 if ((error = gcov_is_error ()))
279 goto read_error;
282 f_ix = ~0u;
283 /* Check program & object summary */
284 while (1)
286 gcov_position_t base = gcov_position ();
287 int is_program;
289 tag = gcov_read_unsigned ();
290 if (!tag)
291 break;
292 length = gcov_read_unsigned ();
293 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
294 if (length != GCOV_TAG_SUMMARY_LENGTH
295 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
296 goto read_mismatch;
297 gcov_read_summary (is_program ? &program : &object);
298 if ((error = gcov_is_error ()))
299 goto read_error;
300 if (is_program && program.checksum == gcov_crc32)
302 summary_pos = base;
303 goto rewrite;
308 if (!gcov_is_eof ())
310 read_error:;
311 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
312 : "profiling:%s:Error merging\n", gi_ptr->filename);
313 goto read_fatal;
315 rewrite:;
316 gcov_rewrite ();
317 if (!summary_pos)
318 memset (&program, 0, sizeof (program));
320 /* Merge the summaries. */
321 f_ix = ~0u;
322 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
324 cs_obj = &object.ctrs[t_ix];
325 cs_tobj = &this_object.ctrs[t_ix];
326 cs_prg = &program.ctrs[t_ix];
327 cs_tprg = &this_program.ctrs[t_ix];
328 cs_all = &all.ctrs[t_ix];
330 if ((1 << t_ix) & gi_ptr->ctr_mask)
332 if (!cs_obj->runs++)
333 cs_obj->num = cs_tobj->num;
334 else if (cs_obj->num != cs_tobj->num)
335 goto read_mismatch;
336 cs_obj->sum_all += cs_tobj->sum_all;
337 if (cs_obj->run_max < cs_tobj->run_max)
338 cs_obj->run_max = cs_tobj->run_max;
339 cs_obj->sum_max += cs_tobj->run_max;
341 if (!cs_prg->runs++)
342 cs_prg->num = cs_tprg->num;
343 else if (cs_prg->num != cs_tprg->num)
344 goto read_mismatch;
345 cs_prg->sum_all += cs_tprg->sum_all;
346 if (cs_prg->run_max < cs_tprg->run_max)
347 cs_prg->run_max = cs_tprg->run_max;
348 cs_prg->sum_max += cs_tprg->run_max;
350 else if (cs_obj->num || cs_prg->num)
351 goto read_mismatch;
353 if (!cs_all->runs && cs_prg->runs)
354 memcpy (cs_all, cs_prg, sizeof (*cs_all));
355 else if (!all.checksum
356 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
357 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
359 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
360 gi_ptr->filename, GCOV_LOCKED
361 ? "" : " or concurrent update without locking support");
362 all.checksum = ~0u;
366 c_ix = 0;
367 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
368 if ((1 << t_ix) & gi_ptr->ctr_mask)
370 values[c_ix] = gi_ptr->counts[c_ix].values;
371 c_ix++;
374 program.checksum = gcov_crc32;
376 /* Write out the data. */
377 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
378 gcov_write_unsigned (gi_ptr->stamp);
380 /* Write execution counts for each function. */
381 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
383 fi_ptr = (const struct gcov_fn_info *)
384 ((const char *) gi_ptr->functions + f_ix * fi_stride);
386 /* Announce function. */
387 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
388 gcov_write_unsigned (fi_ptr->ident);
389 gcov_write_unsigned (fi_ptr->checksum);
391 c_ix = 0;
392 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
394 gcov_type *c_ptr;
396 if (!((1 << t_ix) & gi_ptr->ctr_mask))
397 continue;
399 n_counts = fi_ptr->n_ctrs[c_ix];
401 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
402 GCOV_TAG_COUNTER_LENGTH (n_counts));
403 c_ptr = values[c_ix];
404 while (n_counts--)
405 gcov_write_counter (*c_ptr++);
407 values[c_ix] = c_ptr;
408 c_ix++;
412 /* Object file summary. */
413 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
415 /* Generate whole program statistics. */
416 gcov_seek (summary_pos);
417 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
418 if ((error = gcov_close ()))
419 fprintf (stderr, error < 0 ?
420 "profiling:%s:Overflow writing\n" :
421 "profiling:%s:Error writing\n",
422 gi_ptr->filename);
426 /* Add a new object file onto the bb chain. Invoked automatically
427 when running an object file's global ctors. */
429 void
430 __gcov_init (struct gcov_info *info)
432 if (!info->version)
433 return;
434 if (gcov_version (info, info->version))
436 const char *ptr = info->filename;
437 gcov_unsigned_t crc32 = gcov_crc32;
441 unsigned ix;
442 gcov_unsigned_t value = *ptr << 24;
444 for (ix = 8; ix--; value <<= 1)
446 gcov_unsigned_t feedback;
448 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
449 crc32 <<= 1;
450 crc32 ^= feedback;
453 while (*ptr++);
455 gcov_crc32 = crc32;
457 if (!gcov_list)
458 atexit (gcov_exit);
460 info->next = gcov_list;
461 gcov_list = info;
463 info->version = 0;
466 /* Called before fork or exec - write out profile information gathered so
467 far and reset it to zero. This avoids duplication or loss of the
468 profile information gathered so far. */
470 void
471 __gcov_flush (void)
473 const struct gcov_info *gi_ptr;
475 gcov_exit ();
476 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
478 unsigned t_ix;
479 const struct gcov_ctr_info *ci_ptr;
481 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
482 if ((1 << t_ix) & gi_ptr->ctr_mask)
484 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
485 ci_ptr++;
490 #endif /* L_gcov */
492 #ifdef L_gcov_merge_add
493 /* The profile merging function that just adds the counters. It is given
494 an array COUNTERS of N_COUNTERS old counters and it reads the same number
495 of counters from the gcov file. */
496 void
497 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
499 for (; n_counters; counters++, n_counters--)
500 *counters += gcov_read_counter ();
502 #endif /* L_gcov_merge_add */
504 #ifdef L_gcov_merge_single
505 /* The profile merging function for choosing the most common value.
506 It is given an array COUNTERS of N_COUNTERS old counters and it
507 reads the same number of counters from the gcov file. The counters
508 are split into 3-tuples where the members of the tuple have
509 meanings:
511 -- the stored candidate on the most common value of the measured entity
512 -- counter
513 -- total number of evaluations of the value */
514 void
515 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
517 unsigned i, n_measures;
518 gcov_type value, counter, all;
520 GCOV_CHECK (!(n_counters % 3));
521 n_measures = n_counters / 3;
522 for (i = 0; i < n_measures; i++, counters += 3)
524 value = gcov_read_counter ();
525 counter = gcov_read_counter ();
526 all = gcov_read_counter ();
528 if (counters[0] == value)
529 counters[1] += counter;
530 else if (counter > counters[1])
532 counters[0] = value;
533 counters[1] = counter - counters[1];
535 else
536 counters[1] -= counter;
537 counters[2] += all;
540 #endif /* L_gcov_merge_single */
542 #ifdef L_gcov_merge_delta
543 /* The profile merging function for choosing the most common
544 difference between two consecutive evaluations of the value. It is
545 given an array COUNTERS of N_COUNTERS old counters and it reads the
546 same number of counters from the gcov file. The counters are split
547 into 4-tuples where the members of the tuple have meanings:
549 -- the last value of the measured entity
550 -- the stored candidate on the most common difference
551 -- counter
552 -- total number of evaluations of the value */
553 void
554 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
556 unsigned i, n_measures;
557 gcov_type last, value, counter, all;
559 GCOV_CHECK (!(n_counters % 4));
560 n_measures = n_counters / 4;
561 for (i = 0; i < n_measures; i++, counters += 4)
563 last = gcov_read_counter ();
564 value = gcov_read_counter ();
565 counter = gcov_read_counter ();
566 all = gcov_read_counter ();
568 if (counters[1] == value)
569 counters[2] += counter;
570 else if (counter > counters[2])
572 counters[1] = value;
573 counters[2] = counter - counters[2];
575 else
576 counters[2] -= counter;
577 counters[3] += all;
580 #endif /* L_gcov_merge_delta */
582 #endif /* inhibit_libc */