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