1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2023 Free Software Foundation, Inc.
5 This file is part of GCC.
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
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
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.
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/>. */
29 /* Return 1, if all counter values are zero, otherwise 0. */
32 are_all_counters_zero (const struct gcov_ctr_info
*ci_ptr
)
34 for (unsigned i
= 0; i
< ci_ptr
->num
; i
++)
35 if (ci_ptr
->values
[i
] != 0)
41 #if defined(inhibit_libc)
42 /* If libc and its header files are not available, provide dummy functions. */
45 void __gcov_init (struct gcov_info
*p
__attribute__ ((unused
))) {}
48 #else /* inhibit_libc */
54 #elif GCOV_LOCKED_WITH_LOCKING
56 #include <sys/locking.h>
64 #endif /* inhibit_libc */
66 #if defined(L_gcov) && !defined(inhibit_libc)
70 #if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL
71 #define NEED_L_GCOV_INFO_TO_GCDA
75 /* A utility function for outputting errors. */
76 static int gcov_error (const char *, ...);
79 static void gcov_error_exit (void);
84 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
88 struct gcov_fn_buffer
*next
;
90 struct gcov_fn_info info
;
91 /* note gcov_fn_info ends in a trailing array. */
94 struct gcov_summary_buffer
96 struct gcov_summary_buffer
*next
;
97 struct gcov_summary summary
;
100 /* A struct that bundles all the related information about the
105 char *filename
; /* filename buffer */
106 int strip
; /* leading chars to strip from filename */
107 char *prefix
; /* prefix string */
110 static struct gcov_fn_buffer
*
111 free_fn_data (const struct gcov_info
*gi_ptr
, struct gcov_fn_buffer
*buffer
,
114 struct gcov_fn_buffer
*next
;
115 unsigned ix
, n_ctr
= 0;
121 for (ix
= 0; ix
!= limit
; ix
++)
122 if (gi_ptr
->merge
[ix
])
123 free (buffer
->info
.ctrs
[n_ctr
++].values
);
128 static struct gcov_fn_buffer
**
129 buffer_fn_data (const char *filename
, const struct gcov_info
*gi_ptr
,
130 struct gcov_fn_buffer
**end_ptr
, unsigned fn_ix
)
132 unsigned n_ctrs
= 0, ix
= 0;
133 struct gcov_fn_buffer
*fn_buffer
;
136 for (ix
= GCOV_COUNTERS
; ix
--;)
137 if (gi_ptr
->merge
[ix
])
140 len
= sizeof (*fn_buffer
) + sizeof (fn_buffer
->info
.ctrs
[0]) * n_ctrs
;
141 fn_buffer
= (struct gcov_fn_buffer
*) xmalloc (len
);
147 fn_buffer
->fn_ix
= fn_ix
;
148 fn_buffer
->info
.ident
= gcov_read_unsigned ();
149 fn_buffer
->info
.lineno_checksum
= gcov_read_unsigned ();
150 fn_buffer
->info
.cfg_checksum
= gcov_read_unsigned ();
152 for (n_ctrs
= ix
= 0; ix
!= GCOV_COUNTERS
; ix
++)
154 gcov_unsigned_t length
;
157 if (!gi_ptr
->merge
[ix
])
160 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix
))
166 length
= GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
167 len
= length
* sizeof (gcov_type
);
168 values
= (gcov_type
*) xmalloc (len
);
172 fn_buffer
->info
.ctrs
[n_ctrs
].num
= length
;
173 fn_buffer
->info
.ctrs
[n_ctrs
].values
= values
;
176 *values
++ = gcov_read_counter ();
180 *end_ptr
= fn_buffer
;
181 return &fn_buffer
->next
;
184 gcov_error (GCOV_PROF_PREFIX
"Function %u %s %u \n", filename
, fn_ix
,
185 len
? "cannot allocate" : "counter mismatch", len
? len
: ix
);
187 return (struct gcov_fn_buffer
**)free_fn_data (gi_ptr
, fn_buffer
, ix
);
190 /* Convert VERSION into a string description and return the it.
191 BUFFER is used for storage of the string. The code should be
192 aligned wit gcov-iov.c. */
195 gcov_version_string (char *buffer
, char version
[4])
197 if (version
[0] < 'A' || version
[0] > 'Z'
198 || version
[1] < '0' || version
[1] > '9'
199 || version
[2] < '0' || version
[2] > '9')
200 sprintf (buffer
, "(unknown)");
203 unsigned major
= 10 * (version
[0] - 'A') + (version
[1] - '0');
204 unsigned minor
= version
[2] - '0';
205 sprintf (buffer
, "%u.%u (%s)", major
, minor
,
206 version
[3] == '*' ? "release" : "experimental");
211 /* Check if VERSION of the info block PTR matches libgcov one.
212 Return 1 on success, or zero in case of versions mismatch.
213 If FILENAME is not NULL, its value used for reporting purposes
214 instead of value from the info block. */
217 gcov_version (struct gcov_info
*ptr
, gcov_unsigned_t version
,
218 const char *filename
)
220 if (version
!= GCOV_VERSION
)
223 char ver_string
[128], expected_string
[128];
225 GCOV_UNSIGNED2STRING (v
, version
);
226 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
228 gcov_error (GCOV_PROF_PREFIX
"Version mismatch - expected %s (%.4s) "
230 filename
? filename
: ptr
->filename
,
231 gcov_version_string (expected_string
, e
), e
,
232 gcov_version_string (ver_string
, v
), v
);
238 /* buffer for the fn_data from another program. */
239 static struct gcov_fn_buffer
*fn_buffer
;
241 /* Including system dependent components. */
242 #include "libgcov-driver-system.c"
244 /* This function merges counters in GI_PTR to an existing gcda file.
246 Return -1 on error. In this case, caller will goto read_fatal. */
249 merge_one_data (const char *filename
,
250 struct gcov_info
*gi_ptr
,
251 struct gcov_summary
*summary
)
253 gcov_unsigned_t tag
, length
;
257 struct gcov_fn_buffer
**fn_tail
= &fn_buffer
;
259 length
= gcov_read_unsigned ();
260 if (!gcov_version (gi_ptr
, length
, filename
))
263 /* Skip timestamp. */
264 gcov_read_unsigned ();
266 length
= gcov_read_unsigned ();
267 if (length
!= gi_ptr
->checksum
)
269 /* Read from a different compilation. Overwrite the file. */
270 gcov_error (GCOV_PROF_PREFIX
"overwriting an existing profile data "
271 "with a different checksum\n", filename
);
275 tag
= gcov_read_unsigned ();
276 if (tag
!= GCOV_TAG_OBJECT_SUMMARY
)
278 length
= gcov_read_unsigned ();
279 gcc_assert (length
> 0);
280 gcov_read_summary (summary
);
282 tag
= gcov_read_unsigned ();
283 /* Merge execution counts for each function. */
284 for (f_ix
= 0; (unsigned)f_ix
!= gi_ptr
->n_functions
;
285 f_ix
++, tag
= gcov_read_unsigned ())
287 const struct gcov_ctr_info
*ci_ptr
;
288 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
290 if (tag
!= GCOV_TAG_FUNCTION
)
293 length
= gcov_read_unsigned ();
295 /* This function did not appear in the other program.
296 We have nothing to merge. */
299 if (length
!= GCOV_TAG_FUNCTION_LENGTH
)
302 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
304 /* This function appears in the other program. We
305 need to buffer the information in order to write
306 it back out -- we'll be inserting data before
307 this point, so cannot simply keep the data in the
309 fn_tail
= buffer_fn_data (filename
, gi_ptr
, fn_tail
, f_ix
);
315 length
= gcov_read_unsigned ();
316 if (length
!= gfi_ptr
->ident
)
319 length
= gcov_read_unsigned ();
320 if (length
!= gfi_ptr
->lineno_checksum
)
323 length
= gcov_read_unsigned ();
324 if (length
!= gfi_ptr
->cfg_checksum
)
327 ci_ptr
= gfi_ptr
->ctrs
;
328 for (t_ix
= 0; t_ix
< GCOV_COUNTERS
; t_ix
++)
330 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
335 tag
= gcov_read_unsigned ();
336 int read_length
= (int)gcov_read_unsigned ();
337 length
= abs (read_length
);
338 if (tag
!= GCOV_TAG_FOR_COUNTER (t_ix
)
339 || (length
!= GCOV_TAG_COUNTER_LENGTH (ci_ptr
->num
)
340 && t_ix
!= GCOV_COUNTER_V_TOPN
341 && t_ix
!= GCOV_COUNTER_V_INDIR
))
343 /* Merging with all zero counters does not make sense. */
345 (*merge
) (ci_ptr
->values
, ci_ptr
->num
);
348 if ((error
= gcov_is_error ()))
355 gcov_error (GCOV_PROF_PREFIX
"Merge mismatch for %s %u\n",
356 filename
, f_ix
>= 0 ? "function" : "summary",
357 f_ix
< 0 ? -1 - f_ix
: f_ix
);
363 gcov_error (GCOV_PROF_PREFIX
"%s merging\n", filename
,
364 error
< 0 ? "Overflow": "Error");
368 /* Write the DATA of LENGTH characters to the gcov file. */
371 gcov_dump_handler (const void *data
,
373 void *arg ATTRIBUTE_UNUSED
)
375 gcov_write (data
, length
);
378 /* Allocate SIZE characters and return the address of the allocated memory. */
381 gcov_allocate_handler (unsigned size
, void *arg ATTRIBUTE_UNUSED
)
383 return xmalloc (size
);
385 #endif /* NEED_L_GCOV */
387 #if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
388 /* Dump the WORD using the DUMP handler called with ARG. */
391 dump_unsigned (gcov_unsigned_t word
,
392 void (*dump_fn
) (const void *, unsigned, void *),
395 (*dump_fn
) (&word
, sizeof (word
), arg
);
398 /* Dump the COUNTER using the DUMP handler called with ARG. */
401 dump_counter (gcov_type counter
,
402 void (*dump_fn
) (const void *, unsigned, void *),
405 dump_unsigned ((gcov_unsigned_t
)counter
, dump_fn
, arg
);
407 if (sizeof (counter
) > sizeof (gcov_unsigned_t
))
408 dump_unsigned ((gcov_unsigned_t
)(counter
>> 32), dump_fn
, arg
);
410 dump_unsigned (0, dump_fn
, arg
);
413 /* Dump the STRING using the DUMP handler called with ARG. */
417 dump_string (const char *string
,
418 void (*dump_fn
) (const void *, unsigned, void *),
424 length
= strlen (string
) + 1;
426 dump_unsigned (length
, dump_fn
, arg
);
428 (*dump_fn
) (string
, length
, arg
);
431 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
433 /* Store all TOP N counters where each has a dynamic length. */
436 write_topn_counters (const struct gcov_ctr_info
*ci_ptr
,
438 gcov_unsigned_t n_counts
,
439 void (*dump_fn
) (const void *, unsigned, void *),
440 void *(*allocate_fn
)(unsigned, void *),
443 unsigned counters
= n_counts
/ GCOV_TOPN_MEM_COUNTERS
;
444 gcc_assert (n_counts
% GCOV_TOPN_MEM_COUNTERS
== 0);
446 /* It can happen in a multi-threaded environment that number of counters is
447 different from the size of the corresponding linked lists. */
448 #define LIST_SIZE_MIN_LENGTH 4 * 1024
450 static unsigned *list_sizes
= NULL
;
451 static unsigned list_size_length
= 0;
453 if (list_sizes
== NULL
|| counters
> list_size_length
)
455 list_size_length
= MAX (LIST_SIZE_MIN_LENGTH
, 2 * counters
);
456 #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
458 = (unsigned *)malloc_mmap (list_size_length
* sizeof (unsigned));
461 /* Malloc fallback. */
462 if (list_sizes
== NULL
)
464 (unsigned *)(*allocate_fn
) (list_size_length
* sizeof (unsigned),
468 unsigned pair_total
= 0;
470 for (unsigned i
= 0; i
< counters
; i
++)
472 gcov_type start
= ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
+ 2];
475 for (struct gcov_kvp
*node
= (struct gcov_kvp
*)(__INTPTR_TYPE__
)start
;
476 node
!= NULL
; node
= node
->next
)
480 list_sizes
[i
] = sizes
;
483 unsigned disk_size
= GCOV_TOPN_DISK_COUNTERS
* counters
+ 2 * pair_total
;
484 dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix
), dump_fn
, arg
),
485 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size
), dump_fn
, arg
);
487 for (unsigned i
= 0; i
< counters
; i
++)
489 dump_counter (ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
], dump_fn
, arg
);
490 dump_counter (list_sizes
[i
], dump_fn
, arg
);
491 gcov_type start
= ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
+ 2];
494 for (struct gcov_kvp
*node
= (struct gcov_kvp
*)(__INTPTR_TYPE__
)start
;
495 j
< list_sizes
[i
]; node
= node
->next
, j
++)
497 dump_counter (node
->value
, dump_fn
, arg
);
498 dump_counter (node
->count
, dump_fn
, arg
);
503 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
504 the case of appending to an existing file, SUMMARY_POS will be non-zero.
505 We will write the file starting from SUMMAY_POS. */
508 write_one_data (const struct gcov_info
*gi_ptr
,
509 const struct gcov_summary
*prg_p ATTRIBUTE_UNUSED
,
510 void (*dump_fn
) (const void *, unsigned, void *),
511 void *(*allocate_fn
) (unsigned, void *),
516 dump_unsigned (GCOV_DATA_MAGIC
, dump_fn
, arg
);
517 dump_unsigned (GCOV_VERSION
, dump_fn
, arg
);
518 dump_unsigned (gi_ptr
->stamp
, dump_fn
, arg
);
519 dump_unsigned (gi_ptr
->checksum
, dump_fn
, arg
);
522 /* Generate whole program statistics. */
523 gcov_write_object_summary (prg_p
);
526 /* Write execution counts for each function. */
527 for (f_ix
= 0; f_ix
!= gi_ptr
->n_functions
; f_ix
++)
530 unsigned buffered
= 0;
532 const struct gcov_fn_info
*gfi_ptr
;
533 const struct gcov_ctr_info
*ci_ptr
;
534 gcov_unsigned_t length
;
538 if (fn_buffer
&& fn_buffer
->fn_ix
== f_ix
)
540 /* Buffered data from another program. */
542 gfi_ptr
= &fn_buffer
->info
;
543 length
= GCOV_TAG_FUNCTION_LENGTH
;
548 gfi_ptr
= gi_ptr
->functions
[f_ix
];
549 if (gfi_ptr
&& gfi_ptr
->key
== gi_ptr
)
550 length
= GCOV_TAG_FUNCTION_LENGTH
;
555 dump_unsigned (GCOV_TAG_FUNCTION
, dump_fn
, arg
);
556 dump_unsigned (length
, dump_fn
, arg
);
560 dump_unsigned (gfi_ptr
->ident
, dump_fn
, arg
);
561 dump_unsigned (gfi_ptr
->lineno_checksum
, dump_fn
, arg
);
562 dump_unsigned (gfi_ptr
->cfg_checksum
, dump_fn
, arg
);
564 ci_ptr
= gfi_ptr
->ctrs
;
565 for (t_ix
= 0; t_ix
< GCOV_COUNTERS
; t_ix
++)
567 gcov_position_t n_counts
;
569 if (!gi_ptr
->merge
[t_ix
])
572 n_counts
= ci_ptr
->num
;
574 if (t_ix
== GCOV_COUNTER_V_TOPN
|| t_ix
== GCOV_COUNTER_V_INDIR
)
575 write_topn_counters (ci_ptr
, t_ix
, n_counts
, dump_fn
, allocate_fn
,
579 dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix
), dump_fn
, arg
);
580 if (are_all_counters_zero (ci_ptr
))
581 /* Do not stream when all counters are zero. */
582 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts
),
586 dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts
),
588 for (unsigned i
= 0; i
< n_counts
; i
++)
589 dump_counter (ci_ptr
->values
[i
], dump_fn
, arg
);
597 fn_buffer
= free_fn_data (gi_ptr
, fn_buffer
, GCOV_COUNTERS
);
601 dump_unsigned (0, dump_fn
, arg
);
603 #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
606 /* Dump the coverage counts for one gcov_info object. We merge with existing
607 counts when possible, to avoid growing the .da files ad infinitum. We use
608 this program's checksum to make sure we only accumulate whole program
609 statistics to the correct summary. An object file might be embedded
610 in two separate programs, and we must keep the two program
611 summaries separate. */
614 dump_one_gcov (struct gcov_info
*gi_ptr
, struct gcov_filename
*gf
,
615 unsigned run_counted ATTRIBUTE_UNUSED
,
616 gcov_type run_max ATTRIBUTE_UNUSED
, int mode
)
618 struct gcov_summary summary
= {};
623 error
= gcov_exit_open_gcda_file (gi_ptr
, gf
, mode
);
627 tag
= gcov_read_unsigned ();
630 /* Merge data from file. */
631 if (tag
!= GCOV_DATA_MAGIC
)
633 gcov_error (GCOV_PROF_PREFIX
"Not a gcov data file\n",
637 error
= merge_one_data (gf
->filename
, gi_ptr
, &summary
);
648 summary
.sum_max
+= run_max
;
651 summary
= gi_ptr
->summary
;
654 write_one_data (gi_ptr
, &summary
, gcov_dump_handler
, gcov_allocate_handler
,
660 fn_buffer
= free_fn_data (gi_ptr
, fn_buffer
, GCOV_COUNTERS
);
662 if ((error
= gcov_close ()))
663 gcov_error ((error
< 0 ? GCOV_PROF_PREFIX
"Overflow writing\n"
664 : GCOV_PROF_PREFIX
"Error writing\n"), gf
->filename
);
668 /* Dump all the coverage counts for the program. It first computes program
669 summary and then traverses gcov_list list and dumps the gcov_info
670 objects one by one. Use MODE to open files. */
676 gcov_do_dump (struct gcov_info
*list
, int run_counted
, int mode
)
678 struct gcov_info
*gi_ptr
;
679 struct gcov_filename gf
;
681 /* Compute run_max of this program run. */
682 gcov_type run_max
= 0;
683 for (gi_ptr
= list
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
684 for (unsigned f_ix
= 0; (unsigned)f_ix
!= gi_ptr
->n_functions
; f_ix
++)
686 const struct gcov_ctr_info
*cinfo
687 = &gi_ptr
->functions
[f_ix
]->ctrs
[GCOV_COUNTER_ARCS
];
689 for (unsigned i
= 0; i
< cinfo
->num
; i
++)
690 if (run_max
< cinfo
->values
[i
])
691 run_max
= cinfo
->values
[i
];
694 allocate_filename_struct (&gf
);
696 /* Now merge each file. */
697 for (gi_ptr
= list
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
699 dump_one_gcov (gi_ptr
, &gf
, run_counted
, run_max
, mode
);
708 __attribute__ ((unused
))
709 gcov_get_filename (struct gcov_info
*list
)
711 return list
->filename
;
717 __gcov_dump_one (struct gcov_root
*root
)
722 gcov_do_dump (root
->list
, root
->run_counted
, 0);
725 root
->run_counted
= 1;
728 /* Per-dynamic-object gcov state. */
729 struct gcov_root __gcov_root
;
731 /* Exactly one of these will be live in the process image. */
732 struct gcov_master __gcov_master
=
735 /* Dynamic pool for gcov_kvp structures. */
736 struct gcov_kvp
*__gcov_kvp_dynamic_pool
;
738 /* Index into __gcov_kvp_dynamic_pool array. */
739 unsigned __gcov_kvp_dynamic_pool_index
;
741 /* Size of _gcov_kvp_dynamic_pool array. */
742 unsigned __gcov_kvp_dynamic_pool_size
;
747 __gcov_dump_one (&__gcov_root
);
748 if (__gcov_root
.next
)
749 __gcov_root
.next
->prev
= __gcov_root
.prev
;
750 if (__gcov_root
.prev
)
751 __gcov_root
.prev
->next
= __gcov_root
.next
;
753 __gcov_master
.root
= __gcov_root
.next
;
758 /* Add a new object file onto the bb chain. Invoked automatically
759 when running an object file's global ctors. */
762 __gcov_init (struct gcov_info
*info
)
764 if (!info
->version
|| !info
->n_functions
)
766 if (gcov_version (info
, info
->version
, 0))
768 if (!__gcov_root
.list
)
770 /* Add to master list and at exit function. */
771 if (gcov_version (NULL
, __gcov_master
.version
, "<master>"))
773 __gcov_root
.next
= __gcov_master
.root
;
774 if (__gcov_master
.root
)
775 __gcov_master
.root
->prev
= &__gcov_root
;
776 __gcov_master
.root
= &__gcov_root
;
780 info
->next
= __gcov_root
.list
;
781 __gcov_root
.list
= info
;
784 #endif /* !IN_GCOV_TOOL */
785 #endif /* NEED_L_GCOV */
787 #ifdef NEED_L_GCOV_INFO_TO_GCDA
788 /* Convert the gcov info to a gcda data stream. It is intended for
789 freestanding environments which do not support the C library file I/O. */
792 __gcov_info_to_gcda (const struct gcov_info
*gi_ptr
,
793 void (*filename_fn
) (const char *, void *),
794 void (*dump_fn
) (const void *, unsigned, void *),
795 void *(*allocate_fn
) (unsigned, void *),
798 (*filename_fn
) (gi_ptr
->filename
, arg
);
799 write_one_data (gi_ptr
, NULL
, dump_fn
, allocate_fn
, arg
);
802 /* Convert the filename to a gcfn data stream. It is intended for
803 freestanding environments which do not support the C library file I/O. */
806 __gcov_filename_to_gcfn (const char *filename
,
807 void (*dump_fn
) (const void *, unsigned, void *),
810 dump_unsigned (GCOV_FILENAME_MAGIC
, dump_fn
, arg
);
811 dump_unsigned (GCOV_VERSION
, dump_fn
, arg
);
812 dump_string (filename
, dump_fn
, arg
);
814 #endif /* NEED_L_GCOV_INFO_TO_GCDA */