]> gcc.gnu.org Git - gcc.git/blame - gcc/libgcov.c
tree.h (default_flag_random_seed): Remove.
[gcc.git] / gcc / libgcov.c
CommitLineData
23af32e6
NS
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.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13In addition to the permissions in the GNU General Public License, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file. (The General Public License restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combine
20executable.)
21
22GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23WARRANTY; without even the implied warranty of MERCHANTABILITY or
24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received a copy of the GNU General Public License
28along with GCC; see the file COPYING. If not, write to the Free
29Software Foundation, 59 Temple Place - Suite 330, Boston, MA
3002111-1307, USA. */
31
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. */
35
36#include "tconfig.h"
37#include "tsystem.h"
38#include "coretypes.h"
39#include "tm.h"
40
474f141e
NS
41#if defined(inhibit_libc)
42#define IN_LIBGCOV (-1)
43#else
23af32e6
NS
44#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
45#include <stdio.h>
474f141e
NS
46#define IN_LIBGCOV 1
47#if defined(L_gcov)
48#define GCOV_LINKAGE /* nothing */
49#endif
50#endif
51#include "gcov-io.h"
52
53#if defined(inhibit_libc)
54/* If libc and its header files are not available, provide dummy functions. */
55
56#ifdef L_gcov
57void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
58void __gcov_flush (void) {}
59#endif
60
61#ifdef L_gcov_merge_add
62void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
63 unsigned n_counters __attribute__ ((unused))) {}
64#endif
65
af166e5d
ZD
66#ifdef L_gcov_merge_single
67void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
68 unsigned n_counters __attribute__ ((unused))) {}
69#endif
70
71#ifdef L_gcov_merge_delta
72void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
73 unsigned n_counters __attribute__ ((unused))) {}
74#endif
75
474f141e 76#else
23af32e6 77
23af32e6 78#include <string.h>
474f141e 79#if GCOV_LOCKED
23af32e6
NS
80#include <fcntl.h>
81#include <errno.h>
82#endif
09780dfb
ZD
83
84#ifdef L_gcov
ca29da43 85#include "gcov-io.c"
23af32e6
NS
86
87/* Chain of per-object gcov structures. */
88static struct gcov_info *gcov_list;
89
90/* A program checksum allows us to distinguish program data for an
91 object file included in multiple programs. */
9b514d25 92static gcov_unsigned_t gcov_crc32;
23af32e6
NS
93
94static void
9b514d25 95gcov_version_mismatch (struct gcov_info *ptr, gcov_unsigned_t version)
23af32e6 96{
9b514d25 97 gcov_unsigned_t expected = GCOV_VERSION;
23af32e6
NS
98 unsigned ix;
99 char e[4], v[4];
100
101 for (ix = 4; ix--; expected >>= 8, version >>= 8)
102 {
103 e[ix] = expected;
104 v[ix] = version;
105 }
106
107 fprintf (stderr,
108 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
109 ptr->filename, e, v);
110}
111
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. */
118
119static void
120gcov_exit (void)
121{
cdb23767
NS
122 struct gcov_info *gi_ptr;
123 struct gcov_summary this_program;
124 struct gcov_summary all;
125
126 memset (&all, 0, sizeof (all));
127 /* Find the totals for this execution. */
128 memset (&this_program, 0, sizeof (this_program));
129 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
d101590b 130 {
cdb23767
NS
131 const struct gcov_ctr_info *ci_ptr;
132 struct gcov_ctr_summary *cs_ptr;
133 unsigned t_ix;
134
135 for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
9b514d25 136 t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
cdb23767
NS
137 if ((1 << t_ix) & gi_ptr->ctr_mask)
138 {
139 const gcov_type *c_ptr;
9b514d25 140 gcov_unsigned_t c_num;
cdb23767
NS
141
142 cs_ptr->num += ci_ptr->num;
143 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
144 {
145 cs_ptr->sum_all += *c_ptr;
146 if (cs_ptr->run_max < *c_ptr)
147 cs_ptr->run_max = *c_ptr;
148 }
149 ci_ptr++;
150 }
d101590b 151 }
cdb23767 152
f9da5064 153 /* Now merge each file. */
cdb23767 154 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
23af32e6 155 {
cdb23767
NS
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, t_ix, f_ix;
162 const struct gcov_ctr_info *ci_ptr;
163 struct gcov_ctr_summary *cs_ptr;
164 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
7d63a2fa 165 int error = 0;
546d2adb 166 int merging;
9b514d25 167 gcov_unsigned_t tag, length;
7d63a2fa 168 gcov_position_t summary_pos = 0;
cdb23767
NS
169
170 /* Totals for this object file. */
171 memset (&this_object, 0, sizeof (this_object));
172 for (t_ix = c_ix = 0,
173 ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
9b514d25 174 t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++)
cdb23767
NS
175 if ((1 << t_ix) & gi_ptr->ctr_mask)
176 {
177 const gcov_type *c_ptr;
9b514d25 178 gcov_unsigned_t c_num;
cdb23767
NS
179
180 cs_ptr->num += ci_ptr->num;
181 values[c_ix] = ci_ptr->values;
182 for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
183 {
184 cs_ptr->sum_all += *c_ptr;
185 if (cs_ptr->run_max < *c_ptr)
186 cs_ptr->run_max = *c_ptr;
187 }
188 c_ix++;
189 ci_ptr++;
190 }
191
192 /* Calculate the function_info stride. This depends on the
193 number of counter types being measured. */
194 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
195 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
cb9e4555 196 {
cdb23767
NS
197 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
198 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
cb9e4555 199 }
546d2adb 200
cdb23767
NS
201 /* Open for modification, if possible */
202 merging = gcov_open (gi_ptr->filename, 0);
546d2adb 203 if (!merging)
23af32e6 204 {
cdb23767 205 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
23af32e6
NS
206 continue;
207 }
546d2adb
NS
208
209 if (merging > 0)
23af32e6
NS
210 {
211 /* Merge data from file. */
94de45d9 212 if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
23af32e6
NS
213 {
214 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
cdb23767 215 gi_ptr->filename);
23af32e6 216 read_fatal:;
546d2adb 217 gcov_close ();
23af32e6
NS
218 continue;
219 }
94de45d9
NS
220 length = gcov_read_unsigned ();
221 if (length != GCOV_VERSION)
23af32e6 222 {
cdb23767 223 gcov_version_mismatch (gi_ptr, length);
23af32e6
NS
224 goto read_fatal;
225 }
226
227 /* Merge execution counts for each function. */
796621e8
NS
228 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions;
229 f_ix--;
cdb23767
NS
230 fi_ptr = (const struct gcov_fn_info *)
231 ((const char *) fi_ptr + fi_stride))
23af32e6 232 {
94de45d9
NS
233 tag = gcov_read_unsigned ();
234 length = gcov_read_unsigned ();
23af32e6 235
f9da5064 236 /* Check function. */
796621e8 237 if (tag != GCOV_TAG_FUNCTION
474f141e 238 || length != GCOV_TAG_FUNCTION_LENGTH
796621e8
NS
239 || gcov_read_unsigned () != fi_ptr->ident
240 || gcov_read_unsigned () != fi_ptr->checksum)
23af32e6
NS
241 {
242 read_mismatch:;
cdb23767
NS
243 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
244 gi_ptr->filename,
796621e8 245 f_ix + 1 ? "function" : "summaries");
23af32e6
NS
246 goto read_fatal;
247 }
cb9e4555 248
cdb23767
NS
249 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
250 if ((1 << t_ix) & gi_ptr->ctr_mask)
251 {
474f141e
NS
252 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
253 gcov_merge_fn merge = gi_ptr->counts[c_ix].merge;
cdb23767
NS
254
255 tag = gcov_read_unsigned ();
256 length = gcov_read_unsigned ();
cdb23767 257 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
474f141e 258 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
cdb23767 259 goto read_mismatch;
09780dfb
ZD
260 (*merge) (values[c_ix], n_counts);
261 values[c_ix] += n_counts;
cdb23767 262 c_ix++;
cb9e4555 263 }
94de45d9
NS
264 if ((error = gcov_is_error ()))
265 goto read_error;
23af32e6
NS
266 }
267
474f141e 268 /* Check program & object summary */
7d63a2fa 269 while (1)
23af32e6 270 {
9b514d25 271 gcov_position_t base = gcov_position ();
474f141e
NS
272 int is_program;
273
94de45d9 274 tag = gcov_read_unsigned ();
7d63a2fa
NS
275 if (!tag)
276 break;
474f141e
NS
277 length = gcov_read_unsigned ();
278 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
279 if (length != GCOV_TAG_SUMMARY_LENGTH
280 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
23af32e6 281 goto read_mismatch;
474f141e 282 gcov_read_summary (is_program ? &program : &object);
94de45d9 283 if ((error = gcov_is_error ()))
7d63a2fa
NS
284 goto read_error;
285 if (is_program && program.checksum == gcov_crc32)
94de45d9 286 {
7d63a2fa
NS
287 summary_pos = base;
288 goto rewrite;
94de45d9 289 }
23af32e6 290 }
7d63a2fa
NS
291 if (!gcov_is_eof ())
292 {
293 read_error:;
294 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
295 : "profiling:%s:Error merging\n", gi_ptr->filename);
296 goto read_fatal;
297 }
298 rewrite:;
474f141e 299 gcov_rewrite ();
23af32e6 300 }
cdb23767
NS
301 else
302 memset (&object, 0, sizeof (object));
7d63a2fa 303 if (!summary_pos)
cdb23767 304 memset (&program, 0, sizeof (program));
23af32e6 305
cdb23767 306 /* Merge the summaries. */
796621e8 307 f_ix = ~0u;
cdb23767
NS
308 for (t_ix = c_ix = 0,
309 cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
310 cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
311 cs_all = all.ctrs;
9b514d25 312 t_ix != GCOV_COUNTERS_SUMMABLE;
cdb23767
NS
313 t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
314 {
315 if ((1 << t_ix) & gi_ptr->ctr_mask)
316 {
317 if (!cs_obj->runs++)
318 cs_obj->num = cs_tobj->num;
319 else if (cs_obj->num != cs_tobj->num)
320 goto read_mismatch;
321 cs_obj->sum_all += cs_tobj->sum_all;
322 if (cs_obj->run_max < cs_tobj->run_max)
323 cs_obj->run_max = cs_tobj->run_max;
324 cs_obj->sum_max += cs_tobj->run_max;
325
326 if (!cs_prg->runs++)
327 cs_prg->num = cs_tprg->num;
328 else if (cs_prg->num != cs_tprg->num)
329 goto read_mismatch;
330 cs_prg->sum_all += cs_tprg->sum_all;
331 if (cs_prg->run_max < cs_tprg->run_max)
332 cs_prg->run_max = cs_tprg->run_max;
333 cs_prg->sum_max += cs_tprg->run_max;
334
335 values[c_ix] = gi_ptr->counts[c_ix].values;
336 c_ix++;
337 }
338 else if (cs_obj->num || cs_prg->num)
339 goto read_mismatch;
340
341 if (!cs_all->runs && cs_prg->runs)
342 memcpy (cs_all, cs_prg, sizeof (*cs_all));
343 else if (!all.checksum
344 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
345 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
346 {
347 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
348 gi_ptr->filename, GCOV_LOCKED
349 ? "" : " or concurrent update without locking support");
350 all.checksum = ~0u;
351 }
352 }
353
354 program.checksum = gcov_crc32;
23af32e6
NS
355
356 /* Write out the data. */
9b514d25 357 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
23af32e6
NS
358
359 /* Write execution counts for each function. */
cdb23767
NS
360 for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
361 fi_ptr = (const struct gcov_fn_info *)
362 ((const char *) fi_ptr + fi_stride))
23af32e6
NS
363 {
364 /* Announce function. */
474f141e 365 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
796621e8 366 gcov_write_unsigned (fi_ptr->ident);
cdb23767 367 gcov_write_unsigned (fi_ptr->checksum);
cb9e4555 368
cdb23767
NS
369 for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
370 if ((1 << t_ix) & gi_ptr->ctr_mask)
371 {
474f141e 372 unsigned n_counts = fi_ptr->n_ctrs[c_ix];
cdb23767
NS
373 gcov_type *c_ptr;
374
474f141e
NS
375 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
376 GCOV_TAG_COUNTER_LENGTH (n_counts));
cdb23767 377 c_ptr = values[c_ix];
474f141e
NS
378 while (n_counts--)
379 gcov_write_counter (*c_ptr++);
cdb23767 380 values[c_ix] = c_ptr;
cdb23767
NS
381 c_ix++;
382 }
23af32e6
NS
383 }
384
385 /* Object file summary. */
94de45d9 386 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
23af32e6 387
d101590b 388 /* Generate whole program statistics. */
474f141e 389 gcov_seek (summary_pos);
cdb23767
NS
390 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
391 if ((error = gcov_close ()))
cdb23767
NS
392 fprintf (stderr, error < 0 ?
393 "profiling:%s:Overflow writing\n" :
394 "profiling:%s:Error writing\n",
395 gi_ptr->filename);
23af32e6 396 }
23af32e6
NS
397}
398
399/* Add a new object file onto the bb chain. Invoked automatically
400 when running an object file's global ctors. */
401
402void
403__gcov_init (struct gcov_info *info)
404{
405 if (!info->version)
406 return;
407 if (info->version != GCOV_VERSION)
408 gcov_version_mismatch (info, info->version);
409 else
410 {
411 const char *ptr = info->filename;
9b514d25 412 gcov_unsigned_t crc32 = gcov_crc32;
23af32e6
NS
413
414 do
415 {
416 unsigned ix;
9b514d25 417 gcov_unsigned_t value = *ptr << 24;
23af32e6
NS
418
419 for (ix = 8; ix--; value <<= 1)
420 {
9b514d25 421 gcov_unsigned_t feedback;
23af32e6
NS
422
423 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
424 crc32 <<= 1;
425 crc32 ^= feedback;
426 }
427 }
428 while (*ptr++);
429
430 gcov_crc32 = crc32;
431
432 if (!gcov_list)
433 atexit (gcov_exit);
434
435 info->next = gcov_list;
436 gcov_list = info;
437 }
438 info->version = 0;
439}
440
441/* Called before fork or exec - write out profile information gathered so
442 far and reset it to zero. This avoids duplication or loss of the
443 profile information gathered so far. */
444
445void
446__gcov_flush (void)
447{
cdb23767 448 const struct gcov_info *gi_ptr;
23af32e6
NS
449
450 gcov_exit ();
cdb23767 451 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
23af32e6 452 {
cdb23767
NS
453 unsigned t_ix;
454 const struct gcov_ctr_info *ci_ptr;
23af32e6 455
cdb23767
NS
456 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
457 if ((1 << t_ix) & gi_ptr->ctr_mask)
458 {
459 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
460 ci_ptr++;
461 }
23af32e6
NS
462 }
463}
01e60c33 464
09780dfb
ZD
465#endif /* L_gcov */
466
467#ifdef L_gcov_merge_add
468/* The profile merging function that just adds the counters. It is given
469 an array COUNTERS of N_COUNTERS old counters and it reads the same number
470 of counters from the gcov file. */
471void
9b514d25 472__gcov_merge_add (gcov_type *counters, unsigned n_counters)
09780dfb
ZD
473{
474 for (; n_counters; counters++, n_counters--)
475 *counters += gcov_read_counter ();
476}
477#endif /* L_gcov_merge_add */
478
af166e5d
ZD
479#ifdef L_gcov_merge_single
480/* The profile merging function for choosing the most common value. It is given
481 an array COUNTERS of N_COUNTERS old counters and it reads the same number
482 of counters from the gcov file. The counters are split into 3-tuples
483 where the members of the tuple have meanings:
484 -- the stored candidate on the most common value of the measured entity
485 -- counter
486 -- total number of evaluations of the value */
487void
488__gcov_merge_single (gcov_type *counters, unsigned n_counters)
489{
490 unsigned i, n_measures;
491 gcov_type value, counter, all;
492
493 if (n_counters % 3)
494 abort ();
495
496 n_measures = n_counters / 3;
497 for (i = 0; i < n_measures; i++, counters += 3)
498 {
499 value = gcov_read_counter ();
500 counter = gcov_read_counter ();
501 all = gcov_read_counter ();
502
503 if (counters[0] == value)
504 counters[1] += counter;
505 else if (counter > counters[1])
506 {
507 counters[0] = value;
508 counters[1] = counter - counters[1];
509 }
510 else
511 counters[1] -= counter;
512 counters[2] += all;
513 }
514}
515#endif /* L_gcov_merge_single */
516
517#ifdef L_gcov_merge_delta
518/* The profile merging function for choosing the most common difference between
519 two consecutive evaluations of the value. It is given an array COUNTERS of
520 N_COUNTERS old counters and it reads the same number of counters from the
521 gcov file. The counters are split into 4-tuples where the members of the
522 tuple have meanings:
523 -- the last value of the measured entity
524 -- the stored candidate on the most common difference
525 -- counter
526 -- total number of evaluations of the value */
527void
528__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
529{
530 unsigned i, n_measures;
531 gcov_type last, value, counter, all;
532
533 if (n_counters % 4)
534 abort ();
535
536 n_measures = n_counters / 4;
537 for (i = 0; i < n_measures; i++, counters += 4)
538 {
539 last = gcov_read_counter ();
540 value = gcov_read_counter ();
541 counter = gcov_read_counter ();
542 all = gcov_read_counter ();
543
544 if (counters[1] == value)
545 counters[2] += counter;
546 else if (counter > counters[2])
547 {
548 counters[1] = value;
549 counters[2] = counter - counters[2];
550 }
551 else
552 counters[2] -= counter;
553 counters[3] += all;
554 }
555}
556#endif /* L_gcov_merge_delta */
557
01e60c33 558#endif /* inhibit_libc */
This page took 0.279133 seconds and 5 git commands to generate.