]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-driver.c
[multiple changes]
[thirdparty/gcc.git] / libgcc / libgcov-driver.c
CommitLineData
d6d3f033
RX
1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
ac1dca3c 3/* Copyright (C) 1989-2014 Free Software Foundation, Inc.
d6d3f033
RX
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
40d6b753 26#include "libgcov.h"
d6d3f033
RX
27
28#if defined(inhibit_libc)
29/* If libc and its header files are not available, provide dummy functions. */
30
31#if defined(L_gcov)
32void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
33#endif
34
35#else /* inhibit_libc */
36
37#include <string.h>
38#if GCOV_LOCKED
39#include <fcntl.h>
40#include <errno.h>
41#include <sys/stat.h>
42#endif
43
44#ifdef L_gcov
e3f0315f
TJ
45
46/* A utility function for outputing errors. */
47static int gcov_error (const char *, ...);
48
d6d3f033
RX
49#include "gcov-io.c"
50
51/* The following functions can be called from outside of this file. */
52extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
53extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
d6d3f033
RX
54
55struct gcov_fn_buffer
56{
57 struct gcov_fn_buffer *next;
58 unsigned fn_ix;
59 struct gcov_fn_info info;
60 /* note gcov_fn_info ends in a trailing array. */
61};
62
63struct gcov_summary_buffer
64{
65 struct gcov_summary_buffer *next;
66 struct gcov_summary summary;
67};
68
6dc33097
NS
69/* A struct that bundles all the related information about the
70 gcda filename. */
71
72struct gcov_filename
73{
74 char *filename; /* filename buffer */
75 size_t max_length; /* maximum filename length */
76 int strip; /* leading chars to strip from filename */
77 size_t prefix; /* chars to prepend to filename */
78};
79
d6d3f033 80/* Chain of per-object gcov structures. */
d10ee722
NS
81#ifndef IN_GCOV_TOOL
82/* We need to expose this static variable when compiling for gcov-tool. */
83static
84#endif
85struct gcov_info *gcov_list;
d6d3f033 86
d6d3f033
RX
87/* Flag when the profile has already been dumped via __gcov_dump(). */
88static int gcov_dump_complete;
89
d6d3f033
RX
90static struct gcov_fn_buffer *
91free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
92 unsigned limit)
93{
94 struct gcov_fn_buffer *next;
95 unsigned ix, n_ctr = 0;
96
97 if (!buffer)
98 return 0;
99 next = buffer->next;
100
101 for (ix = 0; ix != limit; ix++)
102 if (gi_ptr->merge[ix])
103 free (buffer->info.ctrs[n_ctr++].values);
104 free (buffer);
105 return next;
106}
107
108static struct gcov_fn_buffer **
109buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
110 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
111{
112 unsigned n_ctrs = 0, ix = 0;
113 struct gcov_fn_buffer *fn_buffer;
114 unsigned len;
115
116 for (ix = GCOV_COUNTERS; ix--;)
117 if (gi_ptr->merge[ix])
118 n_ctrs++;
119
120 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
40d6b753 121 fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
d6d3f033
RX
122
123 if (!fn_buffer)
124 goto fail;
125
126 fn_buffer->next = 0;
127 fn_buffer->fn_ix = fn_ix;
128 fn_buffer->info.ident = gcov_read_unsigned ();
129 fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
130 fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
131
132 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
133 {
134 gcov_unsigned_t length;
135 gcov_type *values;
136
137 if (!gi_ptr->merge[ix])
138 continue;
139
140 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
141 {
142 len = 0;
143 goto fail;
144 }
145
146 length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
147 len = length * sizeof (gcov_type);
40d6b753 148 values = (gcov_type *) xmalloc (len);
d6d3f033
RX
149 if (!values)
150 goto fail;
151
152 fn_buffer->info.ctrs[n_ctrs].num = length;
153 fn_buffer->info.ctrs[n_ctrs].values = values;
154
155 while (length--)
156 *values++ = gcov_read_counter ();
157 n_ctrs++;
158 }
159
160 *end_ptr = fn_buffer;
161 return &fn_buffer->next;
162
163fail:
164 gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix,
165 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
166
167 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
168}
169
170/* Add an unsigned value to the current crc */
171
172static gcov_unsigned_t
173crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
174{
175 unsigned ix;
176
177 for (ix = 32; ix--; value <<= 1)
178 {
179 unsigned feedback;
180
181 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
182 crc32 <<= 1;
183 crc32 ^= feedback;
184 }
185
186 return crc32;
187}
188
189/* Check if VERSION of the info block PTR matches libgcov one.
190 Return 1 on success, or zero in case of versions mismatch.
191 If FILENAME is not NULL, its value used for reporting purposes
192 instead of value from the info block. */
193
194static int
195gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
196 const char *filename)
197{
198 if (version != GCOV_VERSION)
199 {
200 char v[4], e[4];
201
202 GCOV_UNSIGNED2STRING (v, version);
203 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
204
205 gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
206 filename? filename : ptr->filename, e, v);
207 return 0;
208 }
209 return 1;
210}
211
212/* Insert counter VALUE into HISTOGRAM. */
213
214static void
215gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
216{
217 unsigned i;
218
219 i = gcov_histo_index(value);
220 histogram[i].num_counters++;
221 histogram[i].cum_value += value;
222 if (value < histogram[i].min_value)
223 histogram[i].min_value = value;
224}
225
226/* Computes a histogram of the arc counters to place in the summary SUM. */
227
228static void
229gcov_compute_histogram (struct gcov_summary *sum)
230{
231 struct gcov_info *gi_ptr;
232 const struct gcov_fn_info *gfi_ptr;
233 const struct gcov_ctr_info *ci_ptr;
234 struct gcov_ctr_summary *cs_ptr;
235 unsigned t_ix, f_ix, ctr_info_ix, ix;
236 int h_ix;
237
238 /* This currently only applies to arc counters. */
239 t_ix = GCOV_COUNTER_ARCS;
240
241 /* First check if there are any counts recorded for this counter. */
242 cs_ptr = &(sum->ctrs[t_ix]);
243 if (!cs_ptr->num)
244 return;
245
246 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
247 {
248 cs_ptr->histogram[h_ix].num_counters = 0;
249 cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max;
250 cs_ptr->histogram[h_ix].cum_value = 0;
251 }
252
253 /* Walk through all the per-object structures and record each of
254 the count values in histogram. */
255 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
256 {
257 if (!gi_ptr->merge[t_ix])
258 continue;
259
260 /* Find the appropriate index into the gcov_ctr_info array
261 for the counter we are currently working on based on the
262 existence of the merge function pointer for this object. */
263 for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++)
264 {
265 if (gi_ptr->merge[ix])
266 ctr_info_ix++;
267 }
268 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
269 {
270 gfi_ptr = gi_ptr->functions[f_ix];
271
272 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
273 continue;
274
275 ci_ptr = &gfi_ptr->ctrs[ctr_info_ix];
276 for (ix = 0; ix < ci_ptr->num; ix++)
277 gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]);
278 }
279 }
280}
281
d6d3f033
RX
282/* buffer for the fn_data from another program. */
283static struct gcov_fn_buffer *fn_buffer;
284/* buffer for summary from other programs to be written out. */
285static struct gcov_summary_buffer *sum_buffer;
7f369373
JH
286/* If application calls fork or exec multiple times, we end up storing
287 profile repeadely. We should not account this as multiple runs or
288 functions executed once may mistakely become cold. */
289static int run_accounted = 0;
d6d3f033 290
6dc33097
NS
291/* This function computes the program level summary and the histo-gram.
292 It computes and returns CRC32 and stored summary in THIS_PRG.
293 Also determines the longest filename length of the info files. */
d6d3f033 294
867c8b03 295static gcov_unsigned_t
6dc33097
NS
296gcov_exit_compute_summary (struct gcov_summary *this_prg,
297 size_t *max_length)
d6d3f033
RX
298{
299 struct gcov_info *gi_ptr;
300 const struct gcov_fn_info *gfi_ptr;
301 struct gcov_ctr_summary *cs_ptr;
302 const struct gcov_ctr_info *ci_ptr;
303 int f_ix;
304 unsigned t_ix;
305 gcov_unsigned_t c_num;
867c8b03 306 gcov_unsigned_t crc32 = 0;
d6d3f033 307
d6d3f033 308 /* Find the totals for this execution. */
2c973ee7 309 memset (this_prg, 0, sizeof (*this_prg));
6dc33097 310 *max_length = 0;
d6d3f033
RX
311 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
312 {
6dc33097
NS
313 size_t len = strlen (gi_ptr->filename);
314 if (len > *max_length)
315 *max_length = len;
316
d6d3f033
RX
317 crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
318 crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
319
320 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
321 {
322 gfi_ptr = gi_ptr->functions[f_ix];
323
324 if (gfi_ptr && gfi_ptr->key != gi_ptr)
325 gfi_ptr = 0;
326
327 crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
328 crc32 = crc32_unsigned (crc32,
329 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
330 if (!gfi_ptr)
331 continue;
332
333 ci_ptr = gfi_ptr->ctrs;
334 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
335 {
336 if (!gi_ptr->merge[t_ix])
337 continue;
338
2c973ee7 339 cs_ptr = &(this_prg->ctrs[t_ix]);
d6d3f033
RX
340 cs_ptr->num += ci_ptr->num;
341 crc32 = crc32_unsigned (crc32, ci_ptr->num);
342
343 for (c_num = 0; c_num < ci_ptr->num; c_num++)
344 {
345 cs_ptr->sum_all += ci_ptr->values[c_num];
346 if (cs_ptr->run_max < ci_ptr->values[c_num])
347 cs_ptr->run_max = ci_ptr->values[c_num];
348 }
349 ci_ptr++;
350 }
351 }
352 }
2c973ee7 353 gcov_compute_histogram (this_prg);
867c8b03 354 return crc32;
d6d3f033
RX
355}
356
d6d3f033
RX
357/* Including system dependent components. */
358#include "libgcov-driver-system.c"
359
360/* This function merges counters in GI_PTR to an existing gcda file.
361 Return 0 on success.
362 Return -1 on error. In this case, caller will goto read_fatal. */
363
364static int
6dc33097
NS
365gcov_exit_merge_gcda (const char *filename,
366 struct gcov_info *gi_ptr,
d6d3f033 367 struct gcov_summary *prg_p,
2c973ee7 368 struct gcov_summary *this_prg,
d6d3f033 369 gcov_position_t *summary_pos_p,
867c8b03
JH
370 gcov_position_t *eof_pos_p,
371 gcov_unsigned_t crc32)
d6d3f033
RX
372{
373 gcov_unsigned_t tag, length;
374 unsigned t_ix;
375 int f_ix;
376 int error = 0;
377 struct gcov_fn_buffer **fn_tail = &fn_buffer;
378 struct gcov_summary_buffer **sum_tail = &sum_buffer;
379
380 length = gcov_read_unsigned ();
6dc33097 381 if (!gcov_version (gi_ptr, length, filename))
d6d3f033
RX
382 return -1;
383
384 length = gcov_read_unsigned ();
385 if (length != gi_ptr->stamp)
386 /* Read from a different compilation. Overwrite the file. */
387 return 0;
388
389 /* Look for program summary. */
390 for (f_ix = 0;;)
391 {
392 struct gcov_summary tmp;
393
394 *eof_pos_p = gcov_position ();
395 tag = gcov_read_unsigned ();
396 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
397 break;
398
399 f_ix--;
400 length = gcov_read_unsigned ();
401 gcov_read_summary (&tmp);
402 if ((error = gcov_is_error ()))
403 goto read_error;
404 if (*summary_pos_p)
405 {
406 /* Save all summaries after the one that will be
407 merged into below. These will need to be rewritten
408 as histogram merging may change the number of non-zero
409 histogram entries that will be emitted, and thus the
410 size of the merged summary. */
411 (*sum_tail) = (struct gcov_summary_buffer *)
40d6b753 412 xmalloc (sizeof(struct gcov_summary_buffer));
d6d3f033
RX
413 (*sum_tail)->summary = tmp;
414 (*sum_tail)->next = 0;
415 sum_tail = &((*sum_tail)->next);
416 goto next_summary;
417 }
418 if (tmp.checksum != crc32)
419 goto next_summary;
420
421 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
2c973ee7 422 if (tmp.ctrs[t_ix].num != this_prg->ctrs[t_ix].num)
d6d3f033
RX
423 goto next_summary;
424 *prg_p = tmp;
425 *summary_pos_p = *eof_pos_p;
426
427 next_summary:;
428 }
429
430 /* Merge execution counts for each function. */
431 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
432 f_ix++, tag = gcov_read_unsigned ())
433 {
434 const struct gcov_ctr_info *ci_ptr;
435 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
436
437 if (tag != GCOV_TAG_FUNCTION)
438 goto read_mismatch;
439
440 length = gcov_read_unsigned ();
441 if (!length)
442 /* This function did not appear in the other program.
443 We have nothing to merge. */
444 continue;
445
446 if (length != GCOV_TAG_FUNCTION_LENGTH)
447 goto read_mismatch;
448
449 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
450 {
451 /* This function appears in the other program. We
452 need to buffer the information in order to write
453 it back out -- we'll be inserting data before
454 this point, so cannot simply keep the data in the
455 file. */
6dc33097 456 fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
d6d3f033
RX
457 if (!fn_tail)
458 goto read_mismatch;
459 continue;
460 }
461
462 length = gcov_read_unsigned ();
463 if (length != gfi_ptr->ident)
464 goto read_mismatch;
465
466 length = gcov_read_unsigned ();
467 if (length != gfi_ptr->lineno_checksum)
468 goto read_mismatch;
469
470 length = gcov_read_unsigned ();
471 if (length != gfi_ptr->cfg_checksum)
472 goto read_mismatch;
473
474 ci_ptr = gfi_ptr->ctrs;
475 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
476 {
477 gcov_merge_fn merge = gi_ptr->merge[t_ix];
478
479 if (!merge)
480 continue;
481
482 tag = gcov_read_unsigned ();
483 length = gcov_read_unsigned ();
484 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
485 || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
486 goto read_mismatch;
487 (*merge) (ci_ptr->values, ci_ptr->num);
488 ci_ptr++;
489 }
490 if ((error = gcov_is_error ()))
491 goto read_error;
492 }
493
494 if (tag)
495 {
496 read_mismatch:;
497 gcov_error ("profiling:%s:Merge mismatch for %s %u\n",
6dc33097 498 filename, f_ix >= 0 ? "function" : "summary",
d6d3f033
RX
499 f_ix < 0 ? -1 - f_ix : f_ix);
500 return -1;
501 }
502 return 0;
503
504read_error:
6dc33097 505 gcov_error ("profiling:%s:%s merging\n", filename,
d6d3f033
RX
506 error < 0 ? "Overflow": "Error");
507 return -1;
508}
509
510/* Write counters in GI_PTR and the summary in PRG to a gcda file. In
511 the case of appending to an existing file, SUMMARY_POS will be non-zero.
512 We will write the file starting from SUMMAY_POS. */
513
514static void
515gcov_exit_write_gcda (const struct gcov_info *gi_ptr,
516 const struct gcov_summary *prg_p,
517 const gcov_position_t eof_pos,
518 const gcov_position_t summary_pos)
519{
520 unsigned f_ix;
521 struct gcov_summary_buffer *next_sum_buffer;
522
523 /* Write out the data. */
524 if (!eof_pos)
525 {
526 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
527 gcov_write_unsigned (gi_ptr->stamp);
528 }
529
530 if (summary_pos)
531 gcov_seek (summary_pos);
532
533 /* Generate whole program statistics. */
534 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p);
535
536 /* Rewrite all the summaries that were after the summary we merged
537 into. This is necessary as the merged summary may have a different
538 size due to the number of non-zero histogram entries changing after
539 merging. */
540
541 while (sum_buffer)
542 {
543 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
544 next_sum_buffer = sum_buffer->next;
545 free (sum_buffer);
546 sum_buffer = next_sum_buffer;
547 }
548
549 /* Write execution counts for each function. */
550 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
551 {
552 unsigned buffered = 0;
553 const struct gcov_fn_info *gfi_ptr;
554 const struct gcov_ctr_info *ci_ptr;
555 gcov_unsigned_t length;
556 unsigned t_ix;
557
558 if (fn_buffer && fn_buffer->fn_ix == f_ix)
559 {
560 /* Buffered data from another program. */
561 buffered = 1;
562 gfi_ptr = &fn_buffer->info;
563 length = GCOV_TAG_FUNCTION_LENGTH;
564 }
565 else
566 {
567 gfi_ptr = gi_ptr->functions[f_ix];
568 if (gfi_ptr && gfi_ptr->key == gi_ptr)
569 length = GCOV_TAG_FUNCTION_LENGTH;
570 else
571 length = 0;
572 }
573
574 gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
575 if (!length)
576 continue;
577
578 gcov_write_unsigned (gfi_ptr->ident);
579 gcov_write_unsigned (gfi_ptr->lineno_checksum);
580 gcov_write_unsigned (gfi_ptr->cfg_checksum);
581
582 ci_ptr = gfi_ptr->ctrs;
583 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
584 {
585 gcov_unsigned_t n_counts;
586 gcov_type *c_ptr;
587
588 if (!gi_ptr->merge[t_ix])
589 continue;
590
591 n_counts = ci_ptr->num;
592 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
593 GCOV_TAG_COUNTER_LENGTH (n_counts));
594 c_ptr = ci_ptr->values;
595 while (n_counts--)
596 gcov_write_counter (*c_ptr++);
597 ci_ptr++;
598 }
599 if (buffered)
600 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
601 }
602
603 gcov_write_unsigned (0);
604}
605
606/* Helper function for merging summary.
607 Return -1 on error. Return 0 on success. */
608
609static int
6dc33097
NS
610gcov_exit_merge_summary (const char *filename,
611 const struct gcov_info *gi_ptr, struct gcov_summary *prg,
2c973ee7 612 struct gcov_summary *this_prg, gcov_unsigned_t crc32,
7f369373 613 struct gcov_summary *all_prg __attribute__ ((unused)))
d6d3f033
RX
614{
615 struct gcov_ctr_summary *cs_prg, *cs_tprg;
d6d3f033 616 unsigned t_ix;
867c8b03
JH
617#if !GCOV_LOCKED
618 /* summary for all instances of program. */
619 struct gcov_ctr_summary *cs_all;
620#endif
d6d3f033
RX
621
622 /* Merge the summaries. */
623 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
624 {
625 cs_prg = &(prg->ctrs[t_ix]);
2c973ee7 626 cs_tprg = &(this_prg->ctrs[t_ix]);
d6d3f033
RX
627
628 if (gi_ptr->merge[t_ix])
629 {
867c8b03
JH
630 int first = !cs_prg->runs;
631
632 if (!run_accounted)
633 cs_prg->runs++;
867c8b03 634 if (first)
d6d3f033
RX
635 cs_prg->num = cs_tprg->num;
636 cs_prg->sum_all += cs_tprg->sum_all;
637 if (cs_prg->run_max < cs_tprg->run_max)
638 cs_prg->run_max = cs_tprg->run_max;
639 cs_prg->sum_max += cs_tprg->run_max;
867c8b03 640 if (first)
d6d3f033
RX
641 memcpy (cs_prg->histogram, cs_tprg->histogram,
642 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
643 else
644 gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram);
645 }
646 else if (cs_prg->runs)
647 {
648 gcov_error ("profiling:%s:Merge mismatch for summary.\n",
6dc33097 649 filename);
d6d3f033
RX
650 return -1;
651 }
d6d3f033 652#if !GCOV_LOCKED
867c8b03 653 cs_all = &all_prg->ctrs[t_ix];
d6d3f033
RX
654 if (!cs_all->runs && cs_prg->runs)
655 {
656 cs_all->num = cs_prg->num;
657 cs_all->runs = cs_prg->runs;
658 cs_all->sum_all = cs_prg->sum_all;
659 cs_all->run_max = cs_prg->run_max;
660 cs_all->sum_max = cs_prg->sum_max;
661 }
867c8b03 662 else if (!all_prg->checksum
d6d3f033
RX
663 /* Don't compare the histograms, which may have slight
664 variations depending on the order they were updated
665 due to the truncating integer divides used in the
666 merge. */
667 && (cs_all->num != cs_prg->num
668 || cs_all->runs != cs_prg->runs
669 || cs_all->sum_all != cs_prg->sum_all
670 || cs_all->run_max != cs_prg->run_max
671 || cs_all->sum_max != cs_prg->sum_max))
672 {
673 gcov_error ("profiling:%s:Data file mismatch - some "
674 "data files may have been concurrently "
6dc33097 675 "updated without locking support\n", filename);
867c8b03 676 all_prg->checksum = ~0u;
d6d3f033
RX
677 }
678#endif
679 }
40d6b753 680
d6d3f033
RX
681 prg->checksum = crc32;
682
683 return 0;
684}
685
686/* Dump the coverage counts for one gcov_info object. We merge with existing
687 counts when possible, to avoid growing the .da files ad infinitum. We use
688 this program's checksum to make sure we only accumulate whole program
689 statistics to the correct summary. An object file might be embedded
690 in two separate programs, and we must keep the two program
691 summaries separate. */
692
693static void
6dc33097 694gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
2c973ee7
RX
695 gcov_unsigned_t crc32, struct gcov_summary *all_prg,
696 struct gcov_summary *this_prg)
d6d3f033
RX
697{
698 struct gcov_summary prg; /* summary for this object over all program. */
699 int error;
700 gcov_unsigned_t tag;
701 gcov_position_t summary_pos = 0;
702 gcov_position_t eof_pos = 0;
703
704 fn_buffer = 0;
705 sum_buffer = 0;
706
707 error = gcov_exit_open_gcda_file (gi_ptr, gf);
708 if (error == -1)
709 return;
710
711 tag = gcov_read_unsigned ();
712 if (tag)
713 {
714 /* Merge data from file. */
715 if (tag != GCOV_DATA_MAGIC)
716 {
6dc33097 717 gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename);
d6d3f033
RX
718 goto read_fatal;
719 }
6dc33097
NS
720 error = gcov_exit_merge_gcda (gf->filename, gi_ptr, &prg, this_prg,
721 &summary_pos, &eof_pos, crc32);
d6d3f033
RX
722 if (error == -1)
723 goto read_fatal;
724 }
725
726 gcov_rewrite ();
727
728 if (!summary_pos)
729 {
730 memset (&prg, 0, sizeof (prg));
731 summary_pos = eof_pos;
732 }
733
6dc33097
NS
734 error = gcov_exit_merge_summary (gf->filename, gi_ptr, &prg, this_prg,
735 crc32, all_prg);
d6d3f033
RX
736 if (error == -1)
737 goto read_fatal;
738
739 gcov_exit_write_gcda (gi_ptr, &prg, eof_pos, summary_pos);
740 /* fall through */
741
742read_fatal:;
743 while (fn_buffer)
744 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
745
746 if ((error = gcov_close ()))
747 gcov_error (error < 0 ?
748 "profiling:%s:Overflow writing\n" :
749 "profiling:%s:Error writing\n",
6dc33097 750 gf->filename);
d6d3f033
RX
751}
752
753
754/* Dump all the coverage counts for the program. It first computes program
755 summary and then traverses gcov_list list and dumps the gcov_info
756 objects one by one. */
757
758void
759gcov_exit (void)
760{
761 struct gcov_info *gi_ptr;
6dc33097 762 struct gcov_filename gf;
867c8b03
JH
763 gcov_unsigned_t crc32;
764 struct gcov_summary all_prg;
2c973ee7 765 struct gcov_summary this_prg;
d6d3f033
RX
766
767 /* Prevent the counters from being dumped a second time on exit when the
768 application already wrote out the profile using __gcov_dump(). */
769 if (gcov_dump_complete)
770 return;
771
770f687d 772 gcov_dump_complete = 1;
6dc33097
NS
773
774 crc32 = gcov_exit_compute_summary (&this_prg, &gf.max_length);
d6d3f033
RX
775
776 allocate_filename_struct (&gf);
867c8b03
JH
777#if !GCOV_LOCKED
778 memset (&all_prg, 0, sizeof (all_prg));
779#endif
d6d3f033
RX
780
781 /* Now merge each file. */
782 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
2c973ee7 783 gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg, &this_prg);
7f369373 784 run_accounted = 1;
d6d3f033 785
6dc33097 786 free (gf.filename);
d6d3f033
RX
787}
788
789/* Reset all counters to zero. */
790
791void
792gcov_clear (void)
793{
794 const struct gcov_info *gi_ptr;
795
770f687d 796 gcov_dump_complete = 0;
d6d3f033
RX
797 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
798 {
799 unsigned f_ix;
800
801 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
802 {
803 unsigned t_ix;
804 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
805
806 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
807 continue;
808 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
809 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
810 {
811 if (!gi_ptr->merge[t_ix])
812 continue;
813
814 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
815 ci_ptr++;
816 }
817 }
818 }
819}
820
821/* Add a new object file onto the bb chain. Invoked automatically
822 when running an object file's global ctors. */
823
824void
825__gcov_init (struct gcov_info *info)
826{
827 if (!info->version || !info->n_functions)
828 return;
829 if (gcov_version (info, info->version, 0))
830 {
d6d3f033
RX
831 if (!gcov_list)
832 atexit (gcov_exit);
833
834 info->next = gcov_list;
835 gcov_list = info;
836 }
837 info->version = 0;
838}
839
840#endif /* L_gcov */
841#endif /* inhibit_libc */