]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-driver.c
Fix parsing of SVN commits in PRs.
[thirdparty/gcc.git] / libgcc / libgcov-driver.c
CommitLineData
d6d3f033
RX
1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
8d9254fc 3/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
d6d3f033
RX
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
40d6b753 26#include "libgcov.h"
512cc015 27#include "gcov-io.h"
d6d3f033
RX
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)
33void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
34#endif
35
36#else /* inhibit_libc */
37
38#include <string.h>
39#if GCOV_LOCKED
40#include <fcntl.h>
41#include <errno.h>
42#include <sys/stat.h>
43#endif
44
45#ifdef L_gcov
e3f0315f 46
8aa5bdd6 47/* A utility function for outputting errors. */
e3f0315f
TJ
48static int gcov_error (const char *, ...);
49
8aa5bdd6
AC
50#if !IN_GCOV_TOOL
51static void gcov_error_exit (void);
52#endif
53
d6d3f033
RX
54#include "gcov-io.c"
55
d273c40a
ML
56#define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
57
d6d3f033
RX
58struct gcov_fn_buffer
59{
60 struct gcov_fn_buffer *next;
61 unsigned fn_ix;
62 struct gcov_fn_info info;
63 /* note gcov_fn_info ends in a trailing array. */
64};
65
66struct gcov_summary_buffer
67{
68 struct gcov_summary_buffer *next;
69 struct gcov_summary summary;
70};
71
6dc33097
NS
72/* A struct that bundles all the related information about the
73 gcda filename. */
74
75struct gcov_filename
76{
77 char *filename; /* filename buffer */
6dc33097 78 int strip; /* leading chars to strip from filename */
6c086e8c 79 char *prefix; /* prefix string */
6dc33097
NS
80};
81
d6d3f033
RX
82static struct gcov_fn_buffer *
83free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
84 unsigned limit)
85{
86 struct gcov_fn_buffer *next;
87 unsigned ix, n_ctr = 0;
88
89 if (!buffer)
90 return 0;
91 next = buffer->next;
92
93 for (ix = 0; ix != limit; ix++)
94 if (gi_ptr->merge[ix])
95 free (buffer->info.ctrs[n_ctr++].values);
96 free (buffer);
97 return next;
98}
99
100static struct gcov_fn_buffer **
101buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
102 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
103{
104 unsigned n_ctrs = 0, ix = 0;
105 struct gcov_fn_buffer *fn_buffer;
106 unsigned len;
107
108 for (ix = GCOV_COUNTERS; ix--;)
109 if (gi_ptr->merge[ix])
110 n_ctrs++;
111
112 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
40d6b753 113 fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
d6d3f033
RX
114
115 if (!fn_buffer)
116 goto fail;
117
118 fn_buffer->next = 0;
119 fn_buffer->fn_ix = fn_ix;
120 fn_buffer->info.ident = gcov_read_unsigned ();
121 fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
122 fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
123
124 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
125 {
126 gcov_unsigned_t length;
127 gcov_type *values;
128
129 if (!gi_ptr->merge[ix])
130 continue;
131
132 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
133 {
134 len = 0;
135 goto fail;
136 }
137
138 length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
139 len = length * sizeof (gcov_type);
40d6b753 140 values = (gcov_type *) xmalloc (len);
d6d3f033
RX
141 if (!values)
142 goto fail;
143
144 fn_buffer->info.ctrs[n_ctrs].num = length;
145 fn_buffer->info.ctrs[n_ctrs].values = values;
146
147 while (length--)
148 *values++ = gcov_read_counter ();
149 n_ctrs++;
150 }
151
152 *end_ptr = fn_buffer;
153 return &fn_buffer->next;
154
155fail:
d273c40a 156 gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
d6d3f033
RX
157 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
158
159 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
160}
161
be9d9fdb
ML
162/* Convert VERSION into a string description and return the it.
163 BUFFER is used for storage of the string. The code should be
164 aligned wit gcov-iov.c. */
165
166static char *
167gcov_version_string (char *buffer, char version[4])
168{
169 if (version[0] < 'A' || version[0] > 'Z'
170 || version[1] < '0' || version[1] > '9'
171 || version[2] < '0' || version[2] > '9')
172 sprintf (buffer, "(unknown)");
173 else
174 {
175 unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
176 unsigned minor = version[2] - '0';
177 sprintf (buffer, "%u.%u (%s)", major, minor,
178 version[3] == '*' ? "release" : "experimental");
179 }
180 return buffer;
181}
182
d6d3f033
RX
183/* Check if VERSION of the info block PTR matches libgcov one.
184 Return 1 on success, or zero in case of versions mismatch.
185 If FILENAME is not NULL, its value used for reporting purposes
186 instead of value from the info block. */
187
188static int
189gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
190 const char *filename)
191{
192 if (version != GCOV_VERSION)
193 {
194 char v[4], e[4];
be9d9fdb 195 char version_string[128], expected_string[128];
d6d3f033
RX
196
197 GCOV_UNSIGNED2STRING (v, version);
198 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
199
d273c40a 200 gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
be9d9fdb
ML
201 "got %s (%.4s)\n",
202 filename? filename : ptr->filename,
203 gcov_version_string (expected_string, e), e,
204 gcov_version_string (version_string, v), v);
d6d3f033
RX
205 return 0;
206 }
207 return 1;
208}
209
d6d3f033
RX
210/* buffer for the fn_data from another program. */
211static struct gcov_fn_buffer *fn_buffer;
d6d3f033 212
d6d3f033
RX
213/* Including system dependent components. */
214#include "libgcov-driver-system.c"
215
5f32f9cf
ML
216/* Prune TOP N value COUNTERS. It's needed in order to preserve
217 reproducibility of builds. */
218
219static void
220prune_topn_counter (gcov_type *counters, gcov_type all)
221{
5f32f9cf 222 for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
e9ee848d
ML
223 if (counters[2 * i + 1] < all)
224 {
225 counters[2 * i] = 0;
226 counters[2 * i + 1] = 0;
227 }
5f32f9cf
ML
228}
229
230/* Prune counters so that they are ready to store or merge. */
231
232static void
233prune_counters (struct gcov_info *gi)
234{
235 for (unsigned i = 0; i < gi->n_functions; i++)
236 {
237 const struct gcov_fn_info *gfi = gi->functions[i];
238 const struct gcov_ctr_info *ci = gfi->ctrs;
239
240 for (unsigned j = 0; j < GCOV_COUNTERS; j++)
241 {
242 if (gi->merge[j] == NULL)
243 continue;
244
245 if (gi->merge[j] == __gcov_merge_topn)
246 {
247 gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS));
248 for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS);
249 k++)
250 {
251 gcov_type *counters
252 = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS);
253 prune_topn_counter (counters + 1, *counters);
254 }
255 }
256 ci++;
257 }
258 }
259}
260
d6d3f033
RX
261/* This function merges counters in GI_PTR to an existing gcda file.
262 Return 0 on success.
263 Return -1 on error. In this case, caller will goto read_fatal. */
264
265static int
19926161
NS
266merge_one_data (const char *filename,
267 struct gcov_info *gi_ptr,
512cc015 268 struct gcov_summary *summary)
d6d3f033
RX
269{
270 gcov_unsigned_t tag, length;
271 unsigned t_ix;
512cc015 272 int f_ix = -1;
d6d3f033
RX
273 int error = 0;
274 struct gcov_fn_buffer **fn_tail = &fn_buffer;
d6d3f033
RX
275
276 length = gcov_read_unsigned ();
6dc33097 277 if (!gcov_version (gi_ptr, length, filename))
d6d3f033
RX
278 return -1;
279
280 length = gcov_read_unsigned ();
281 if (length != gi_ptr->stamp)
0e8f29da
ML
282 {
283 /* Read from a different compilation. Overwrite the file. */
d273c40a 284 gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
0e8f29da
ML
285 "with a different timestamp\n", filename);
286 return 0;
287 }
d6d3f033 288
512cc015
ML
289 tag = gcov_read_unsigned ();
290 if (tag != GCOV_TAG_OBJECT_SUMMARY)
291 goto read_mismatch;
292 length = gcov_read_unsigned ();
293 gcc_assert (length > 0);
294 gcov_read_summary (summary);
d6d3f033 295
512cc015 296 tag = gcov_read_unsigned ();
d6d3f033
RX
297 /* Merge execution counts for each function. */
298 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
299 f_ix++, tag = gcov_read_unsigned ())
300 {
301 const struct gcov_ctr_info *ci_ptr;
302 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
303
304 if (tag != GCOV_TAG_FUNCTION)
305 goto read_mismatch;
306
307 length = gcov_read_unsigned ();
308 if (!length)
309 /* This function did not appear in the other program.
310 We have nothing to merge. */
311 continue;
312
313 if (length != GCOV_TAG_FUNCTION_LENGTH)
314 goto read_mismatch;
315
316 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
317 {
318 /* This function appears in the other program. We
319 need to buffer the information in order to write
320 it back out -- we'll be inserting data before
321 this point, so cannot simply keep the data in the
322 file. */
6dc33097 323 fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
d6d3f033
RX
324 if (!fn_tail)
325 goto read_mismatch;
326 continue;
327 }
328
329 length = gcov_read_unsigned ();
330 if (length != gfi_ptr->ident)
331 goto read_mismatch;
332
333 length = gcov_read_unsigned ();
334 if (length != gfi_ptr->lineno_checksum)
335 goto read_mismatch;
336
337 length = gcov_read_unsigned ();
338 if (length != gfi_ptr->cfg_checksum)
339 goto read_mismatch;
340
341 ci_ptr = gfi_ptr->ctrs;
342 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
343 {
344 gcov_merge_fn merge = gi_ptr->merge[t_ix];
345
346 if (!merge)
347 continue;
348
349 tag = gcov_read_unsigned ();
350 length = gcov_read_unsigned ();
351 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
352 || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
353 goto read_mismatch;
354 (*merge) (ci_ptr->values, ci_ptr->num);
355 ci_ptr++;
356 }
357 if ((error = gcov_is_error ()))
358 goto read_error;
359 }
360
361 if (tag)
362 {
363 read_mismatch:;
d273c40a 364 gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
6dc33097 365 filename, f_ix >= 0 ? "function" : "summary",
d6d3f033
RX
366 f_ix < 0 ? -1 - f_ix : f_ix);
367 return -1;
368 }
369 return 0;
370
371read_error:
d273c40a 372 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
d6d3f033
RX
373 error < 0 ? "Overflow": "Error");
374 return -1;
375}
376
377/* Write counters in GI_PTR and the summary in PRG to a gcda file. In
378 the case of appending to an existing file, SUMMARY_POS will be non-zero.
379 We will write the file starting from SUMMAY_POS. */
380
381static void
19926161 382write_one_data (const struct gcov_info *gi_ptr,
512cc015 383 const struct gcov_summary *prg_p)
d6d3f033
RX
384{
385 unsigned f_ix;
d6d3f033 386
512cc015
ML
387 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
388 gcov_write_unsigned (gi_ptr->stamp);
d6d3f033
RX
389
390 /* Generate whole program statistics. */
512cc015 391 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
d6d3f033
RX
392
393 /* Write execution counts for each function. */
394 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
395 {
396 unsigned buffered = 0;
397 const struct gcov_fn_info *gfi_ptr;
398 const struct gcov_ctr_info *ci_ptr;
399 gcov_unsigned_t length;
400 unsigned t_ix;
401
402 if (fn_buffer && fn_buffer->fn_ix == f_ix)
403 {
404 /* Buffered data from another program. */
405 buffered = 1;
406 gfi_ptr = &fn_buffer->info;
407 length = GCOV_TAG_FUNCTION_LENGTH;
408 }
409 else
410 {
411 gfi_ptr = gi_ptr->functions[f_ix];
412 if (gfi_ptr && gfi_ptr->key == gi_ptr)
413 length = GCOV_TAG_FUNCTION_LENGTH;
414 else
415 length = 0;
416 }
417
418 gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
419 if (!length)
420 continue;
421
422 gcov_write_unsigned (gfi_ptr->ident);
423 gcov_write_unsigned (gfi_ptr->lineno_checksum);
424 gcov_write_unsigned (gfi_ptr->cfg_checksum);
425
426 ci_ptr = gfi_ptr->ctrs;
427 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
428 {
429 gcov_unsigned_t n_counts;
430 gcov_type *c_ptr;
431
432 if (!gi_ptr->merge[t_ix])
433 continue;
434
435 n_counts = ci_ptr->num;
436 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
437 GCOV_TAG_COUNTER_LENGTH (n_counts));
438 c_ptr = ci_ptr->values;
439 while (n_counts--)
440 gcov_write_counter (*c_ptr++);
441 ci_ptr++;
442 }
443 if (buffered)
444 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
445 }
446
447 gcov_write_unsigned (0);
448}
449
512cc015 450/* Helper function for merging summary. */
d6d3f033 451
512cc015
ML
452static void
453merge_summary (int run_counted, struct gcov_summary *summary,
454 gcov_type run_max)
d6d3f033 455{
7f3577f5 456 if (!run_counted)
7f3577f5 457 {
512cc015
ML
458 summary->runs++;
459 summary->sum_max += run_max;
d6d3f033 460 }
d6d3f033
RX
461}
462
463/* Dump the coverage counts for one gcov_info object. We merge with existing
464 counts when possible, to avoid growing the .da files ad infinitum. We use
465 this program's checksum to make sure we only accumulate whole program
466 statistics to the correct summary. An object file might be embedded
467 in two separate programs, and we must keep the two program
468 summaries separate. */
469
470static void
19926161 471dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
512cc015 472 unsigned run_counted, gcov_type run_max)
d6d3f033 473{
512cc015 474 struct gcov_summary summary = {};
d6d3f033
RX
475 int error;
476 gcov_unsigned_t tag;
d6d3f033 477 fn_buffer = 0;
d6d3f033 478
5f32f9cf
ML
479 /* Prune current counters before we merge them. */
480 prune_counters (gi_ptr);
481
d6d3f033
RX
482 error = gcov_exit_open_gcda_file (gi_ptr, gf);
483 if (error == -1)
484 return;
485
486 tag = gcov_read_unsigned ();
487 if (tag)
488 {
489 /* Merge data from file. */
490 if (tag != GCOV_DATA_MAGIC)
491 {
d273c40a
ML
492 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
493 gf->filename);
d6d3f033
RX
494 goto read_fatal;
495 }
512cc015 496 error = merge_one_data (gf->filename, gi_ptr, &summary);
d6d3f033
RX
497 if (error == -1)
498 goto read_fatal;
499 }
500
501 gcov_rewrite ();
502
512cc015 503 merge_summary (run_counted, &summary, run_max);
d6d3f033 504
512cc015 505 write_one_data (gi_ptr, &summary);
d6d3f033
RX
506 /* fall through */
507
508read_fatal:;
509 while (fn_buffer)
510 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
511
512 if ((error = gcov_close ()))
513 gcov_error (error < 0 ?
d273c40a
ML
514 GCOV_PROF_PREFIX "Overflow writing\n" :
515 GCOV_PROF_PREFIX "Error writing\n",
6dc33097 516 gf->filename);
d6d3f033
RX
517}
518
519
520/* Dump all the coverage counts for the program. It first computes program
521 summary and then traverses gcov_list list and dumps the gcov_info
522 objects one by one. */
523
4303c581
NS
524#if !IN_GCOV_TOOL
525static
526#endif
527void
19926161 528gcov_do_dump (struct gcov_info *list, int run_counted)
d6d3f033
RX
529{
530 struct gcov_info *gi_ptr;
6dc33097 531 struct gcov_filename gf;
d6d3f033 532
512cc015
ML
533 /* Compute run_max of this program run. */
534 gcov_type run_max = 0;
535 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
536 for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
537 {
538 const struct gcov_ctr_info *cinfo
539 = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
540
541 for (unsigned i = 0; i < cinfo->num; i++)
542 if (run_max < cinfo->values[i])
543 run_max = cinfo->values[i];
544 }
d6d3f033
RX
545
546 allocate_filename_struct (&gf);
547
548 /* Now merge each file. */
19926161 549 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
6c086e8c 550 {
512cc015 551 dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
6c086e8c
ML
552 free (gf.filename);
553 }
d6d3f033 554
6c086e8c 555 free (gf.prefix);
d6d3f033
RX
556}
557
63971184
ML
558#if IN_GCOV_TOOL
559const char *
560__attribute__ ((unused))
561gcov_get_filename (struct gcov_info *list)
562{
563 return list->filename;
564}
565#endif
566
b98a872b 567#if !IN_GCOV_TOOL
19926161 568void
4303c581 569__gcov_dump_one (struct gcov_root *root)
19926161 570{
4303c581 571 if (root->dumped)
19926161
NS
572 return;
573
4303c581 574 gcov_do_dump (root->list, root->run_counted);
19926161 575
4303c581
NS
576 root->dumped = 1;
577 root->run_counted = 1;
19926161
NS
578}
579
cadb2b96 580/* Per-dynamic-object gcov state. */
4303c581 581struct gcov_root __gcov_root;
d6d3f033 582
cadb2b96
NS
583/* Exactly one of these will be live in the process image. */
584struct gcov_master __gcov_master =
585 {GCOV_VERSION, 0};
586
8c9434c2
ML
587void
588__gcov_exit (void)
d6d3f033 589{
4303c581 590 __gcov_dump_one (&__gcov_root);
cadb2b96
NS
591 if (__gcov_root.next)
592 __gcov_root.next->prev = __gcov_root.prev;
593 if (__gcov_root.prev)
594 __gcov_root.prev->next = __gcov_root.next;
595 else
596 __gcov_master.root = __gcov_root.next;
8aa5bdd6
AC
597
598 gcov_error_exit ();
d6d3f033
RX
599}
600
601/* Add a new object file onto the bb chain. Invoked automatically
602 when running an object file's global ctors. */
603
604void
605__gcov_init (struct gcov_info *info)
606{
607 if (!info->version || !info->n_functions)
608 return;
609 if (gcov_version (info, info->version, 0))
610 {
4303c581 611 if (!__gcov_root.list)
cadb2b96
NS
612 {
613 /* Add to master list and at exit function. */
614 if (gcov_version (NULL, __gcov_master.version, "<master>"))
615 {
616 __gcov_root.next = __gcov_master.root;
617 if (__gcov_master.root)
618 __gcov_master.root->prev = &__gcov_root;
619 __gcov_master.root = &__gcov_root;
620 }
cadb2b96 621 }
d6d3f033 622
4303c581
NS
623 info->next = __gcov_root.list;
624 __gcov_root.list = info;
d6d3f033 625 }
d6d3f033 626}
b98a872b 627#endif /* !IN_GCOV_TOOL */
d6d3f033
RX
628#endif /* L_gcov */
629#endif /* inhibit_libc */