]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/libgcov-driver.c
Daily bump.
[thirdparty/gcc.git] / libgcc / libgcov-driver.c
1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2021 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 "libgcov.h"
27 #include "gcov-io.h"
28
29 #if defined(inhibit_libc)
30 /* If libc and its header files are not available, provide dummy functions. */
31
32 #if defined(L_gcov)
33 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
34 #endif
35
36 #else /* inhibit_libc */
37
38 #include <string.h>
39
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
49
50 #if HAVE_SYS_MMAN_H
51 #include <sys/mman.h>
52 #endif
53
54 #ifdef L_gcov
55
56 /* A utility function for outputting errors. */
57 static int gcov_error (const char *, ...);
58
59 #if !IN_GCOV_TOOL
60 static void gcov_error_exit (void);
61 #endif
62
63 #include "gcov-io.c"
64
65 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
66
67 struct gcov_fn_buffer
68 {
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. */
73 };
74
75 struct gcov_summary_buffer
76 {
77 struct gcov_summary_buffer *next;
78 struct gcov_summary summary;
79 };
80
81 /* A struct that bundles all the related information about the
82 gcda filename. */
83
84 struct gcov_filename
85 {
86 char *filename; /* filename buffer */
87 int strip; /* leading chars to strip from filename */
88 char *prefix; /* prefix string */
89 };
90
91 static struct gcov_fn_buffer *
92 free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
93 unsigned limit)
94 {
95 struct gcov_fn_buffer *next;
96 unsigned ix, n_ctr = 0;
97
98 if (!buffer)
99 return 0;
100 next = buffer->next;
101
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;
107 }
108
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)
112 {
113 unsigned n_ctrs = 0, ix = 0;
114 struct gcov_fn_buffer *fn_buffer;
115 unsigned len;
116
117 for (ix = GCOV_COUNTERS; ix--;)
118 if (gi_ptr->merge[ix])
119 n_ctrs++;
120
121 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
122 fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
123
124 if (!fn_buffer)
125 goto fail;
126
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 ();
132
133 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
134 {
135 gcov_unsigned_t length;
136 gcov_type *values;
137
138 if (!gi_ptr->merge[ix])
139 continue;
140
141 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
142 {
143 len = 0;
144 goto fail;
145 }
146
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;
152
153 fn_buffer->info.ctrs[n_ctrs].num = length;
154 fn_buffer->info.ctrs[n_ctrs].values = values;
155
156 while (length--)
157 *values++ = gcov_read_counter ();
158 n_ctrs++;
159 }
160
161 *end_ptr = fn_buffer;
162 return &fn_buffer->next;
163
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);
167
168 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
169 }
170
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. */
174
175 static char *
176 gcov_version_string (char *buffer, char version[4])
177 {
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
183 {
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");
188 }
189 return buffer;
190 }
191
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. */
196
197 static int
198 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
199 const char *filename)
200 {
201 if (version != GCOV_VERSION)
202 {
203 char v[4], e[4];
204 char ver_string[128], expected_string[128];
205
206 GCOV_UNSIGNED2STRING (v, version);
207 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
208
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;
215 }
216 return 1;
217 }
218
219 /* buffer for the fn_data from another program. */
220 static struct gcov_fn_buffer *fn_buffer;
221
222 /* Including system dependent components. */
223 #include "libgcov-driver-system.c"
224
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. */
228
229 static int
230 merge_one_data (const char *filename,
231 struct gcov_info *gi_ptr,
232 struct gcov_summary *summary)
233 {
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;
239
240 length = gcov_read_unsigned ();
241 if (!gcov_version (gi_ptr, length, filename))
242 return -1;
243
244 length = gcov_read_unsigned ();
245 if (length != gi_ptr->stamp)
246 {
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;
251 }
252
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);
259
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 ())
264 {
265 const struct gcov_ctr_info *ci_ptr;
266 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
267
268 if (tag != GCOV_TAG_FUNCTION)
269 goto read_mismatch;
270
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;
276
277 if (length != GCOV_TAG_FUNCTION_LENGTH)
278 goto read_mismatch;
279
280 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
281 {
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;
291 }
292
293 length = gcov_read_unsigned ();
294 if (length != gfi_ptr->ident)
295 goto read_mismatch;
296
297 length = gcov_read_unsigned ();
298 if (length != gfi_ptr->lineno_checksum)
299 goto read_mismatch;
300
301 length = gcov_read_unsigned ();
302 if (length != gfi_ptr->cfg_checksum)
303 goto read_mismatch;
304
305 ci_ptr = gfi_ptr->ctrs;
306 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
307 {
308 gcov_merge_fn merge = gi_ptr->merge[t_ix];
309
310 if (!merge)
311 continue;
312
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++;
325 }
326 if ((error = gcov_is_error ()))
327 goto read_error;
328 }
329
330 if (tag)
331 {
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;
337 }
338 return 0;
339
340 read_error:
341 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
342 error < 0 ? "Overflow": "Error");
343 return -1;
344 }
345
346 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
347
348 /* Store all TOP N counters where each has a dynamic length. */
349
350 static void
351 write_topn_counters (const struct gcov_ctr_info *ci_ptr,
352 unsigned t_ix,
353 gcov_unsigned_t n_counts)
354 {
355 unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
356 gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
357
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
361
362 static unsigned *list_sizes = NULL;
363 static unsigned list_size_length = 0;
364
365 if (list_sizes == NULL || counters > list_size_length)
366 {
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
372
373 /* Malloc fallback. */
374 if (list_sizes == NULL)
375 list_sizes = (unsigned *)xmalloc (list_size_length * sizeof (unsigned));
376 }
377
378 memset (list_sizes, 0, counters * sizeof (unsigned));
379 unsigned pair_total = 0;
380
381 for (unsigned i = 0; i < counters; i++)
382 {
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)
386 {
387 ++pair_total;
388 ++list_sizes[i];
389 }
390 }
391
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));
395
396 for (unsigned i = 0; i < counters; i++)
397 {
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];
401
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++)
405 {
406 gcov_write_counter (node->value);
407 gcov_write_counter (node->count);
408 }
409 }
410 }
411
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. */
415
416 static void
417 write_one_data (const struct gcov_info *gi_ptr,
418 const struct gcov_summary *prg_p)
419 {
420 unsigned f_ix;
421
422 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
423 gcov_write_unsigned (gi_ptr->stamp);
424
425 /* Generate whole program statistics. */
426 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
427
428 /* Write execution counts for each function. */
429 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
430 {
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;
436
437 if (fn_buffer && fn_buffer->fn_ix == f_ix)
438 {
439 /* Buffered data from another program. */
440 buffered = 1;
441 gfi_ptr = &fn_buffer->info;
442 length = GCOV_TAG_FUNCTION_LENGTH;
443 }
444 else
445 {
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;
451 }
452
453 gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
454 if (!length)
455 continue;
456
457 gcov_write_unsigned (gfi_ptr->ident);
458 gcov_write_unsigned (gfi_ptr->lineno_checksum);
459 gcov_write_unsigned (gfi_ptr->cfg_checksum);
460
461 ci_ptr = gfi_ptr->ctrs;
462 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
463 {
464 gcov_position_t n_counts;
465
466 if (!gi_ptr->merge[t_ix])
467 continue;
468
469 n_counts = ci_ptr->num;
470
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
474 {
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)
479 {
480 all_zeros = 0;
481 break;
482 }
483
484 if (all_zeros)
485 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
486 GCOV_TAG_COUNTER_LENGTH (-n_counts));
487 else
488 {
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]);
493 }
494 }
495
496 ci_ptr++;
497 }
498 if (buffered)
499 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
500 }
501
502 gcov_write_unsigned (0);
503 }
504
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. */
511
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)
516 {
517 struct gcov_summary summary = {};
518 int error;
519 gcov_unsigned_t tag;
520 fn_buffer = 0;
521
522 error = gcov_exit_open_gcda_file (gi_ptr, gf);
523 if (error == -1)
524 return;
525
526 tag = gcov_read_unsigned ();
527 if (tag)
528 {
529 /* Merge data from file. */
530 if (tag != GCOV_DATA_MAGIC)
531 {
532 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
533 gf->filename);
534 goto read_fatal;
535 }
536 error = merge_one_data (gf->filename, gi_ptr, &summary);
537 if (error == -1)
538 goto read_fatal;
539 }
540
541 gcov_rewrite ();
542
543 #if !IN_GCOV_TOOL
544 if (!run_counted)
545 {
546 summary.runs++;
547 summary.sum_max += run_max;
548 }
549 #else
550 summary = gi_ptr->summary;
551 #endif
552
553 write_one_data (gi_ptr, &summary);
554 /* fall through */
555
556 read_fatal:;
557 while (fn_buffer)
558 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
559
560 if ((error = gcov_close ()))
561 gcov_error (error < 0 ?
562 GCOV_PROF_PREFIX "Overflow writing\n" :
563 GCOV_PROF_PREFIX "Error writing\n",
564 gf->filename);
565 }
566
567
568 /* Dump all the coverage counts for the program. It first computes program
569 summary and then traverses gcov_list list and dumps the gcov_info
570 objects one by one. */
571
572 #if !IN_GCOV_TOOL
573 static
574 #endif
575 void
576 gcov_do_dump (struct gcov_info *list, int run_counted)
577 {
578 struct gcov_info *gi_ptr;
579 struct gcov_filename gf;
580
581 /* Compute run_max of this program run. */
582 gcov_type run_max = 0;
583 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
584 for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
585 {
586 const struct gcov_ctr_info *cinfo
587 = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
588
589 for (unsigned i = 0; i < cinfo->num; i++)
590 if (run_max < cinfo->values[i])
591 run_max = cinfo->values[i];
592 }
593
594 allocate_filename_struct (&gf);
595
596 /* Now merge each file. */
597 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
598 {
599 dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
600 free (gf.filename);
601 }
602
603 free (gf.prefix);
604 }
605
606 #if IN_GCOV_TOOL
607 const char *
608 __attribute__ ((unused))
609 gcov_get_filename (struct gcov_info *list)
610 {
611 return list->filename;
612 }
613 #endif
614
615 #if !IN_GCOV_TOOL
616 void
617 __gcov_dump_one (struct gcov_root *root)
618 {
619 if (root->dumped)
620 return;
621
622 gcov_do_dump (root->list, root->run_counted);
623
624 root->dumped = 1;
625 root->run_counted = 1;
626 }
627
628 /* Per-dynamic-object gcov state. */
629 struct gcov_root __gcov_root;
630
631 /* Exactly one of these will be live in the process image. */
632 struct gcov_master __gcov_master =
633 {GCOV_VERSION, 0};
634
635 /* Dynamic pool for gcov_kvp structures. */
636 struct gcov_kvp *__gcov_kvp_dynamic_pool;
637
638 /* Index into __gcov_kvp_dynamic_pool array. */
639 unsigned __gcov_kvp_dynamic_pool_index;
640
641 /* Size of _gcov_kvp_dynamic_pool array. */
642 unsigned __gcov_kvp_dynamic_pool_size;
643
644 void
645 __gcov_exit (void)
646 {
647 __gcov_dump_one (&__gcov_root);
648 if (__gcov_root.next)
649 __gcov_root.next->prev = __gcov_root.prev;
650 if (__gcov_root.prev)
651 __gcov_root.prev->next = __gcov_root.next;
652 else
653 __gcov_master.root = __gcov_root.next;
654
655 gcov_error_exit ();
656 }
657
658 /* Add a new object file onto the bb chain. Invoked automatically
659 when running an object file's global ctors. */
660
661 void
662 __gcov_init (struct gcov_info *info)
663 {
664 if (!info->version || !info->n_functions)
665 return;
666 if (gcov_version (info, info->version, 0))
667 {
668 if (!__gcov_root.list)
669 {
670 /* Add to master list and at exit function. */
671 if (gcov_version (NULL, __gcov_master.version, "<master>"))
672 {
673 __gcov_root.next = __gcov_master.root;
674 if (__gcov_master.root)
675 __gcov_master.root->prev = &__gcov_root;
676 __gcov_master.root = &__gcov_root;
677 }
678 }
679
680 info->next = __gcov_root.list;
681 __gcov_root.list = info;
682 }
683 }
684 #endif /* !IN_GCOV_TOOL */
685 #endif /* L_gcov */
686 #endif /* inhibit_libc */