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