1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2021 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 #if defined(inhibit_libc)
30 /* If libc and its header files are not available, provide dummy functions. */
33 void __gcov_init (struct gcov_info
*p
__attribute__ ((unused
))) {}
36 #else /* inhibit_libc */
44 #elif GCOV_LOCKED_WITH_LOCKING
46 #include <sys/locking.h>
56 /* A utility function for outputting errors. */
57 static int gcov_error (const char *, ...);
60 static void gcov_error_exit (void);
65 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
69 struct gcov_fn_buffer
*next
;
71 struct gcov_fn_info info
;
72 /* note gcov_fn_info ends in a trailing array. */
75 struct gcov_summary_buffer
77 struct gcov_summary_buffer
*next
;
78 struct gcov_summary summary
;
81 /* A struct that bundles all the related information about the
86 char *filename
; /* filename buffer */
87 int strip
; /* leading chars to strip from filename */
88 char *prefix
; /* prefix string */
91 static struct gcov_fn_buffer
*
92 free_fn_data (const struct gcov_info
*gi_ptr
, struct gcov_fn_buffer
*buffer
,
95 struct gcov_fn_buffer
*next
;
96 unsigned ix
, n_ctr
= 0;
102 for (ix
= 0; ix
!= limit
; ix
++)
103 if (gi_ptr
->merge
[ix
])
104 free (buffer
->info
.ctrs
[n_ctr
++].values
);
109 static struct gcov_fn_buffer
**
110 buffer_fn_data (const char *filename
, const struct gcov_info
*gi_ptr
,
111 struct gcov_fn_buffer
**end_ptr
, unsigned fn_ix
)
113 unsigned n_ctrs
= 0, ix
= 0;
114 struct gcov_fn_buffer
*fn_buffer
;
117 for (ix
= GCOV_COUNTERS
; ix
--;)
118 if (gi_ptr
->merge
[ix
])
121 len
= sizeof (*fn_buffer
) + sizeof (fn_buffer
->info
.ctrs
[0]) * n_ctrs
;
122 fn_buffer
= (struct gcov_fn_buffer
*) xmalloc (len
);
128 fn_buffer
->fn_ix
= fn_ix
;
129 fn_buffer
->info
.ident
= gcov_read_unsigned ();
130 fn_buffer
->info
.lineno_checksum
= gcov_read_unsigned ();
131 fn_buffer
->info
.cfg_checksum
= gcov_read_unsigned ();
133 for (n_ctrs
= ix
= 0; ix
!= GCOV_COUNTERS
; ix
++)
135 gcov_unsigned_t length
;
138 if (!gi_ptr
->merge
[ix
])
141 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix
))
147 length
= GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
148 len
= length
* sizeof (gcov_type
);
149 values
= (gcov_type
*) xmalloc (len
);
153 fn_buffer
->info
.ctrs
[n_ctrs
].num
= length
;
154 fn_buffer
->info
.ctrs
[n_ctrs
].values
= values
;
157 *values
++ = gcov_read_counter ();
161 *end_ptr
= fn_buffer
;
162 return &fn_buffer
->next
;
165 gcov_error (GCOV_PROF_PREFIX
"Function %u %s %u \n", filename
, fn_ix
,
166 len
? "cannot allocate" : "counter mismatch", len
? len
: ix
);
168 return (struct gcov_fn_buffer
**)free_fn_data (gi_ptr
, fn_buffer
, ix
);
171 /* Convert VERSION into a string description and return the it.
172 BUFFER is used for storage of the string. The code should be
173 aligned wit gcov-iov.c. */
176 gcov_version_string (char *buffer
, char version
[4])
178 if (version
[0] < 'A' || version
[0] > 'Z'
179 || version
[1] < '0' || version
[1] > '9'
180 || version
[2] < '0' || version
[2] > '9')
181 sprintf (buffer
, "(unknown)");
184 unsigned major
= 10 * (version
[0] - 'A') + (version
[1] - '0');
185 unsigned minor
= version
[2] - '0';
186 sprintf (buffer
, "%u.%u (%s)", major
, minor
,
187 version
[3] == '*' ? "release" : "experimental");
192 /* Check if VERSION of the info block PTR matches libgcov one.
193 Return 1 on success, or zero in case of versions mismatch.
194 If FILENAME is not NULL, its value used for reporting purposes
195 instead of value from the info block. */
198 gcov_version (struct gcov_info
*ptr
, gcov_unsigned_t version
,
199 const char *filename
)
201 if (version
!= GCOV_VERSION
)
204 char ver_string
[128], expected_string
[128];
206 GCOV_UNSIGNED2STRING (v
, version
);
207 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
209 gcov_error (GCOV_PROF_PREFIX
"Version mismatch - expected %s (%.4s) "
211 filename
? filename
: ptr
->filename
,
212 gcov_version_string (expected_string
, e
), e
,
213 gcov_version_string (ver_string
, v
), v
);
219 /* buffer for the fn_data from another program. */
220 static struct gcov_fn_buffer
*fn_buffer
;
222 /* Including system dependent components. */
223 #include "libgcov-driver-system.c"
225 /* This function merges counters in GI_PTR to an existing gcda file.
227 Return -1 on error. In this case, caller will goto read_fatal. */
230 merge_one_data (const char *filename
,
231 struct gcov_info
*gi_ptr
,
232 struct gcov_summary
*summary
)
234 gcov_unsigned_t tag
, length
;
238 struct gcov_fn_buffer
**fn_tail
= &fn_buffer
;
240 length
= gcov_read_unsigned ();
241 if (!gcov_version (gi_ptr
, length
, filename
))
244 length
= gcov_read_unsigned ();
245 if (length
!= gi_ptr
->stamp
)
247 /* Read from a different compilation. Overwrite the file. */
248 gcov_error (GCOV_PROF_PREFIX
"overwriting an existing profile data "
249 "with a different timestamp\n", filename
);
253 tag
= gcov_read_unsigned ();
254 if (tag
!= GCOV_TAG_OBJECT_SUMMARY
)
256 length
= gcov_read_unsigned ();
257 gcc_assert (length
> 0);
258 gcov_read_summary (summary
);
260 tag
= gcov_read_unsigned ();
261 /* Merge execution counts for each function. */
262 for (f_ix
= 0; (unsigned)f_ix
!= gi_ptr
->n_functions
;
263 f_ix
++, tag
= gcov_read_unsigned ())
265 const struct gcov_ctr_info
*ci_ptr
;
266 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
268 if (tag
!= GCOV_TAG_FUNCTION
)
271 length
= gcov_read_unsigned ();
273 /* This function did not appear in the other program.
274 We have nothing to merge. */
277 if (length
!= GCOV_TAG_FUNCTION_LENGTH
)
280 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
282 /* This function appears in the other program. We
283 need to buffer the information in order to write
284 it back out -- we'll be inserting data before
285 this point, so cannot simply keep the data in the
287 fn_tail
= buffer_fn_data (filename
, gi_ptr
, fn_tail
, f_ix
);
293 length
= gcov_read_unsigned ();
294 if (length
!= gfi_ptr
->ident
)
297 length
= gcov_read_unsigned ();
298 if (length
!= gfi_ptr
->lineno_checksum
)
301 length
= gcov_read_unsigned ();
302 if (length
!= gfi_ptr
->cfg_checksum
)
305 ci_ptr
= gfi_ptr
->ctrs
;
306 for (t_ix
= 0; t_ix
< GCOV_COUNTERS
; t_ix
++)
308 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
313 tag
= gcov_read_unsigned ();
314 int read_length
= (int)gcov_read_unsigned ();
315 length
= abs (read_length
);
316 if (tag
!= GCOV_TAG_FOR_COUNTER (t_ix
)
317 || (length
!= GCOV_TAG_COUNTER_LENGTH (ci_ptr
->num
)
318 && t_ix
!= GCOV_COUNTER_V_TOPN
319 && t_ix
!= GCOV_COUNTER_V_INDIR
))
321 /* Merging with all zero counters does not make sense. */
323 (*merge
) (ci_ptr
->values
, ci_ptr
->num
);
326 if ((error
= gcov_is_error ()))
333 gcov_error (GCOV_PROF_PREFIX
"Merge mismatch for %s %u\n",
334 filename
, f_ix
>= 0 ? "function" : "summary",
335 f_ix
< 0 ? -1 - f_ix
: f_ix
);
341 gcov_error (GCOV_PROF_PREFIX
"%s merging\n", filename
,
342 error
< 0 ? "Overflow": "Error");
346 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
348 /* Store all TOP N counters where each has a dynamic length. */
351 write_topn_counters (const struct gcov_ctr_info
*ci_ptr
,
353 gcov_unsigned_t n_counts
)
355 unsigned counters
= n_counts
/ GCOV_TOPN_MEM_COUNTERS
;
356 gcc_assert (n_counts
% GCOV_TOPN_MEM_COUNTERS
== 0);
358 /* It can happen in a multi-threaded environment that number of counters is
359 different from the size of the corresponding linked lists. */
360 #define LIST_SIZE_MIN_LENGTH 4 * 1024
362 static unsigned *list_sizes
= NULL
;
363 static unsigned list_size_length
= 0;
365 if (list_sizes
== NULL
|| counters
> list_size_length
)
367 list_size_length
= MAX (LIST_SIZE_MIN_LENGTH
, 2 * counters
);
370 = (unsigned *)malloc_mmap (list_size_length
* sizeof (unsigned));
373 /* Malloc fallback. */
374 if (list_sizes
== NULL
)
375 list_sizes
= (unsigned *)xmalloc (list_size_length
* sizeof (unsigned));
378 memset (list_sizes
, 0, counters
* sizeof (unsigned));
379 unsigned pair_total
= 0;
381 for (unsigned i
= 0; i
< counters
; i
++)
383 gcov_type start
= ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
+ 2];
384 for (struct gcov_kvp
*node
= (struct gcov_kvp
*)(intptr_t)start
;
385 node
!= NULL
; node
= node
->next
)
392 unsigned disk_size
= GCOV_TOPN_DISK_COUNTERS
* counters
+ 2 * pair_total
;
393 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix
),
394 GCOV_TAG_COUNTER_LENGTH (disk_size
));
396 for (unsigned i
= 0; i
< counters
; i
++)
398 gcov_write_counter (ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
]);
399 gcov_write_counter (list_sizes
[i
]);
400 gcov_type start
= ci_ptr
->values
[GCOV_TOPN_MEM_COUNTERS
* i
+ 2];
403 for (struct gcov_kvp
*node
= (struct gcov_kvp
*)(intptr_t)start
;
404 j
< list_sizes
[i
]; node
= node
->next
, j
++)
406 gcov_write_counter (node
->value
);
407 gcov_write_counter (node
->count
);
412 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
413 the case of appending to an existing file, SUMMARY_POS will be non-zero.
414 We will write the file starting from SUMMAY_POS. */
417 write_one_data (const struct gcov_info
*gi_ptr
,
418 const struct gcov_summary
*prg_p
)
422 gcov_write_tag_length (GCOV_DATA_MAGIC
, GCOV_VERSION
);
423 gcov_write_unsigned (gi_ptr
->stamp
);
425 /* Generate whole program statistics. */
426 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY
, prg_p
);
428 /* Write execution counts for each function. */
429 for (f_ix
= 0; f_ix
!= gi_ptr
->n_functions
; f_ix
++)
431 unsigned buffered
= 0;
432 const struct gcov_fn_info
*gfi_ptr
;
433 const struct gcov_ctr_info
*ci_ptr
;
434 gcov_unsigned_t length
;
437 if (fn_buffer
&& fn_buffer
->fn_ix
== f_ix
)
439 /* Buffered data from another program. */
441 gfi_ptr
= &fn_buffer
->info
;
442 length
= GCOV_TAG_FUNCTION_LENGTH
;
446 gfi_ptr
= gi_ptr
->functions
[f_ix
];
447 if (gfi_ptr
&& gfi_ptr
->key
== gi_ptr
)
448 length
= GCOV_TAG_FUNCTION_LENGTH
;
453 gcov_write_tag_length (GCOV_TAG_FUNCTION
, length
);
457 gcov_write_unsigned (gfi_ptr
->ident
);
458 gcov_write_unsigned (gfi_ptr
->lineno_checksum
);
459 gcov_write_unsigned (gfi_ptr
->cfg_checksum
);
461 ci_ptr
= gfi_ptr
->ctrs
;
462 for (t_ix
= 0; t_ix
< GCOV_COUNTERS
; t_ix
++)
464 gcov_position_t n_counts
;
466 if (!gi_ptr
->merge
[t_ix
])
469 n_counts
= ci_ptr
->num
;
471 if (t_ix
== GCOV_COUNTER_V_TOPN
|| t_ix
== GCOV_COUNTER_V_INDIR
)
472 write_topn_counters (ci_ptr
, t_ix
, n_counts
);
475 /* Do not stream when all counters are zero. */
477 for (unsigned i
= 0; i
< n_counts
; i
++)
478 if (ci_ptr
->values
[i
] != 0)
485 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix
),
486 GCOV_TAG_COUNTER_LENGTH (-n_counts
));
489 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix
),
490 GCOV_TAG_COUNTER_LENGTH (n_counts
));
491 for (unsigned i
= 0; i
< n_counts
; i
++)
492 gcov_write_counter (ci_ptr
->values
[i
]);
499 fn_buffer
= free_fn_data (gi_ptr
, fn_buffer
, GCOV_COUNTERS
);
502 gcov_write_unsigned (0);
505 /* Dump the coverage counts for one gcov_info object. We merge with existing
506 counts when possible, to avoid growing the .da files ad infinitum. We use
507 this program's checksum to make sure we only accumulate whole program
508 statistics to the correct summary. An object file might be embedded
509 in two separate programs, and we must keep the two program
510 summaries separate. */
513 dump_one_gcov (struct gcov_info
*gi_ptr
, struct gcov_filename
*gf
,
514 unsigned run_counted ATTRIBUTE_UNUSED
,
515 gcov_type run_max ATTRIBUTE_UNUSED
)
517 struct gcov_summary summary
= {};
522 error
= gcov_exit_open_gcda_file (gi_ptr
, gf
);
526 tag
= gcov_read_unsigned ();
529 /* Merge data from file. */
530 if (tag
!= GCOV_DATA_MAGIC
)
532 gcov_error (GCOV_PROF_PREFIX
"Not a gcov data file\n",
536 error
= merge_one_data (gf
->filename
, gi_ptr
, &summary
);
547 summary
.sum_max
+= run_max
;
550 summary
= gi_ptr
->summary
;
553 write_one_data (gi_ptr
, &summary
);
558 fn_buffer
= free_fn_data (gi_ptr
, fn_buffer
, GCOV_COUNTERS
);
560 if ((error
= gcov_close ()))
561 gcov_error ((error
< 0 ? GCOV_PROF_PREFIX
"Overflow writing\n"
562 : GCOV_PROF_PREFIX
"Error writing\n"), gf
->filename
);
566 /* Dump all the coverage counts for the program. It first computes program
567 summary and then traverses gcov_list list and dumps the gcov_info
568 objects one by one. */
574 gcov_do_dump (struct gcov_info
*list
, int run_counted
)
576 struct gcov_info
*gi_ptr
;
577 struct gcov_filename gf
;
579 /* Compute run_max of this program run. */
580 gcov_type run_max
= 0;
581 for (gi_ptr
= list
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
582 for (unsigned f_ix
= 0; (unsigned)f_ix
!= gi_ptr
->n_functions
; f_ix
++)
584 const struct gcov_ctr_info
*cinfo
585 = &gi_ptr
->functions
[f_ix
]->ctrs
[GCOV_COUNTER_ARCS
];
587 for (unsigned i
= 0; i
< cinfo
->num
; i
++)
588 if (run_max
< cinfo
->values
[i
])
589 run_max
= cinfo
->values
[i
];
592 allocate_filename_struct (&gf
);
594 /* Now merge each file. */
595 for (gi_ptr
= list
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
597 dump_one_gcov (gi_ptr
, &gf
, run_counted
, run_max
);
606 __attribute__ ((unused
))
607 gcov_get_filename (struct gcov_info
*list
)
609 return list
->filename
;
615 __gcov_dump_one (struct gcov_root
*root
)
620 gcov_do_dump (root
->list
, root
->run_counted
);
623 root
->run_counted
= 1;
626 /* Per-dynamic-object gcov state. */
627 struct gcov_root __gcov_root
;
629 /* Exactly one of these will be live in the process image. */
630 struct gcov_master __gcov_master
=
633 /* Dynamic pool for gcov_kvp structures. */
634 struct gcov_kvp
*__gcov_kvp_dynamic_pool
;
636 /* Index into __gcov_kvp_dynamic_pool array. */
637 unsigned __gcov_kvp_dynamic_pool_index
;
639 /* Size of _gcov_kvp_dynamic_pool array. */
640 unsigned __gcov_kvp_dynamic_pool_size
;
645 __gcov_dump_one (&__gcov_root
);
646 if (__gcov_root
.next
)
647 __gcov_root
.next
->prev
= __gcov_root
.prev
;
648 if (__gcov_root
.prev
)
649 __gcov_root
.prev
->next
= __gcov_root
.next
;
651 __gcov_master
.root
= __gcov_root
.next
;
656 /* Add a new object file onto the bb chain. Invoked automatically
657 when running an object file's global ctors. */
660 __gcov_init (struct gcov_info
*info
)
662 if (!info
->version
|| !info
->n_functions
)
664 if (gcov_version (info
, info
->version
, 0))
666 if (!__gcov_root
.list
)
668 /* Add to master list and at exit function. */
669 if (gcov_version (NULL
, __gcov_master
.version
, "<master>"))
671 __gcov_root
.next
= __gcov_master
.root
;
672 if (__gcov_master
.root
)
673 __gcov_master
.root
->prev
= &__gcov_root
;
674 __gcov_master
.root
= &__gcov_root
;
678 info
->next
= __gcov_root
.list
;
679 __gcov_root
.list
= info
;
682 #endif /* !IN_GCOV_TOOL */
684 #endif /* inhibit_libc */