mklog: add subject line skeleton
[official-gcc.git] / libgcc / libgcov-driver.c
blobdf7ccb235677d96fe4fd61c3b4cc6b8141810812
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
10 version.
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.
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/>. */
26 #include "libgcov.h"
27 #include "gcov-io.h"
29 #if defined(inhibit_libc)
30 /* If libc and its header files are not available, provide dummy functions. */
32 #if defined(L_gcov)
33 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
34 #endif
36 #else /* inhibit_libc */
38 #include <string.h>
40 #if GCOV_LOCKED
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <sys/stat.h>
44 #elif GCOV_LOCKED_WITH_LOCKING
45 #include <fcntl.h>
46 #include <sys/locking.h>
47 #include <sys/stat.h>
48 #endif
50 #if HAVE_SYS_MMAN_H
51 #include <sys/mman.h>
52 #endif
54 #ifdef L_gcov
56 /* A utility function for outputting errors. */
57 static int gcov_error (const char *, ...);
59 #if !IN_GCOV_TOOL
60 static void gcov_error_exit (void);
61 #endif
63 #include "gcov-io.c"
65 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
67 struct gcov_fn_buffer
69 struct gcov_fn_buffer *next;
70 unsigned fn_ix;
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
82 gcda filename. */
84 struct gcov_filename
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,
93 unsigned limit)
95 struct gcov_fn_buffer *next;
96 unsigned ix, n_ctr = 0;
98 if (!buffer)
99 return 0;
100 next = buffer->next;
102 for (ix = 0; ix != limit; ix++)
103 if (gi_ptr->merge[ix])
104 free (buffer->info.ctrs[n_ctr++].values);
105 free (buffer);
106 return next;
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;
115 unsigned len;
117 for (ix = GCOV_COUNTERS; ix--;)
118 if (gi_ptr->merge[ix])
119 n_ctrs++;
121 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
122 fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
124 if (!fn_buffer)
125 goto fail;
127 fn_buffer->next = 0;
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;
136 gcov_type *values;
138 if (!gi_ptr->merge[ix])
139 continue;
141 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
143 len = 0;
144 goto fail;
147 length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
148 len = length * sizeof (gcov_type);
149 values = (gcov_type *) xmalloc (len);
150 if (!values)
151 goto fail;
153 fn_buffer->info.ctrs[n_ctrs].num = length;
154 fn_buffer->info.ctrs[n_ctrs].values = values;
156 while (length--)
157 *values++ = gcov_read_counter ();
158 n_ctrs++;
161 *end_ptr = fn_buffer;
162 return &fn_buffer->next;
164 fail:
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. */
175 static char *
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)");
182 else
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");
189 return buffer;
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. */
197 static int
198 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
199 const char *filename)
201 if (version != GCOV_VERSION)
203 char v[4], e[4];
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) "
210 "got %s (%.4s)\n",
211 filename? filename : ptr->filename,
212 gcov_version_string (expected_string, e), e,
213 gcov_version_string (ver_string, v), v);
214 return 0;
216 return 1;
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.
226 Return 0 on success.
227 Return -1 on error. In this case, caller will goto read_fatal. */
229 static int
230 merge_one_data (const char *filename,
231 struct gcov_info *gi_ptr,
232 struct gcov_summary *summary)
234 gcov_unsigned_t tag, length;
235 unsigned t_ix;
236 int f_ix = -1;
237 int error = 0;
238 struct gcov_fn_buffer **fn_tail = &fn_buffer;
240 length = gcov_read_unsigned ();
241 if (!gcov_version (gi_ptr, length, filename))
242 return -1;
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);
250 return 0;
253 tag = gcov_read_unsigned ();
254 if (tag != GCOV_TAG_OBJECT_SUMMARY)
255 goto read_mismatch;
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)
269 goto read_mismatch;
271 length = gcov_read_unsigned ();
272 if (!length)
273 /* This function did not appear in the other program.
274 We have nothing to merge. */
275 continue;
277 if (length != GCOV_TAG_FUNCTION_LENGTH)
278 goto read_mismatch;
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
286 file. */
287 fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
288 if (!fn_tail)
289 goto read_mismatch;
290 continue;
293 length = gcov_read_unsigned ();
294 if (length != gfi_ptr->ident)
295 goto read_mismatch;
297 length = gcov_read_unsigned ();
298 if (length != gfi_ptr->lineno_checksum)
299 goto read_mismatch;
301 length = gcov_read_unsigned ();
302 if (length != gfi_ptr->cfg_checksum)
303 goto read_mismatch;
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];
310 if (!merge)
311 continue;
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))
320 goto read_mismatch;
321 /* Merging with all zero counters does not make sense. */
322 if (read_length > 0)
323 (*merge) (ci_ptr->values, ci_ptr->num);
324 ci_ptr++;
326 if ((error = gcov_is_error ()))
327 goto read_error;
330 if (tag)
332 read_mismatch:;
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);
336 return -1;
338 return 0;
340 read_error:
341 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
342 error < 0 ? "Overflow": "Error");
343 return -1;
346 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
348 /* Store all TOP N counters where each has a dynamic length. */
350 static void
351 write_topn_counters (const struct gcov_ctr_info *ci_ptr,
352 unsigned t_ix,
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);
368 #if HAVE_SYS_MMAN_H
369 list_sizes
370 = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
371 #endif
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)
387 ++pair_total;
388 ++list_sizes[i];
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];
402 unsigned j = 0;
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. */
416 static void
417 write_one_data (const struct gcov_info *gi_ptr,
418 const struct gcov_summary *prg_p)
420 unsigned f_ix;
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;
435 unsigned t_ix;
437 if (fn_buffer && fn_buffer->fn_ix == f_ix)
439 /* Buffered data from another program. */
440 buffered = 1;
441 gfi_ptr = &fn_buffer->info;
442 length = GCOV_TAG_FUNCTION_LENGTH;
444 else
446 gfi_ptr = gi_ptr->functions[f_ix];
447 if (gfi_ptr && gfi_ptr->key == gi_ptr)
448 length = GCOV_TAG_FUNCTION_LENGTH;
449 else
450 length = 0;
453 gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
454 if (!length)
455 continue;
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])
467 continue;
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);
473 else
475 /* Do not stream when all counters are zero. */
476 int all_zeros = 1;
477 for (unsigned i = 0; i < n_counts; i++)
478 if (ci_ptr->values[i] != 0)
480 all_zeros = 0;
481 break;
484 if (all_zeros)
485 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
486 GCOV_TAG_COUNTER_LENGTH (-n_counts));
487 else
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]);
496 ci_ptr++;
498 if (buffered)
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. */
512 static void
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 = {};
518 int error;
519 gcov_unsigned_t tag;
520 fn_buffer = 0;
522 error = gcov_exit_open_gcda_file (gi_ptr, gf);
523 if (error == -1)
524 return;
526 tag = gcov_read_unsigned ();
527 if (tag)
529 /* Merge data from file. */
530 if (tag != GCOV_DATA_MAGIC)
532 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
533 gf->filename);
534 goto read_fatal;
536 error = merge_one_data (gf->filename, gi_ptr, &summary);
537 if (error == -1)
538 goto read_fatal;
541 gcov_rewrite ();
543 #if !IN_GCOV_TOOL
544 if (!run_counted)
546 summary.runs++;
547 summary.sum_max += run_max;
549 #else
550 summary = gi_ptr->summary;
551 #endif
553 write_one_data (gi_ptr, &summary);
554 /* fall through */
556 read_fatal:;
557 while (fn_buffer)
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. */
570 #if !IN_GCOV_TOOL
571 static
572 #endif
573 void
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);
598 free (gf.filename);
601 free (gf.prefix);
604 #if IN_GCOV_TOOL
605 const char *
606 __attribute__ ((unused))
607 gcov_get_filename (struct gcov_info *list)
609 return list->filename;
611 #endif
613 #if !IN_GCOV_TOOL
614 void
615 __gcov_dump_one (struct gcov_root *root)
617 if (root->dumped)
618 return;
620 gcov_do_dump (root->list, root->run_counted);
622 root->dumped = 1;
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 =
631 {GCOV_VERSION, 0};
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;
642 void
643 __gcov_exit (void)
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;
650 else
651 __gcov_master.root = __gcov_root.next;
653 gcov_error_exit ();
656 /* Add a new object file onto the bb chain. Invoked automatically
657 when running an object file's global ctors. */
659 void
660 __gcov_init (struct gcov_info *info)
662 if (!info->version || !info->n_functions)
663 return;
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 */
683 #endif /* L_gcov */
684 #endif /* inhibit_libc */