]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-driver.c
Daily bump.
[thirdparty/gcc.git] / libgcc / libgcov-driver.c
CommitLineData
d6d3f033
RX
1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
99dee823 3/* Copyright (C) 1989-2021 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>
9ec469f5 39
d6d3f033
RX
40#if GCOV_LOCKED
41#include <fcntl.h>
42#include <errno.h>
43#include <sys/stat.h>
9ec469f5
EB
44#elif GCOV_LOCKED_WITH_LOCKING
45#include <fcntl.h>
46#include <sys/locking.h>
47#include <sys/stat.h>
d6d3f033
RX
48#endif
49
6a8fc0c3
ML
50#if HAVE_SYS_MMAN_H
51#include <sys/mman.h>
52#endif
53
d6d3f033 54#ifdef L_gcov
e3f0315f 55
8aa5bdd6 56/* A utility function for outputting errors. */
e3f0315f
TJ
57static int gcov_error (const char *, ...);
58
8aa5bdd6
AC
59#if !IN_GCOV_TOOL
60static void gcov_error_exit (void);
61#endif
62
d6d3f033
RX
63#include "gcov-io.c"
64
d273c40a
ML
65#define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
66
d6d3f033
RX
67struct 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
75struct gcov_summary_buffer
76{
77 struct gcov_summary_buffer *next;
78 struct gcov_summary summary;
79};
80
6dc33097
NS
81/* A struct that bundles all the related information about the
82 gcda filename. */
83
84struct gcov_filename
85{
86 char *filename; /* filename buffer */
6dc33097 87 int strip; /* leading chars to strip from filename */
6c086e8c 88 char *prefix; /* prefix string */
6dc33097
NS
89};
90
d6d3f033
RX
91static struct gcov_fn_buffer *
92free_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
109static struct gcov_fn_buffer **
110buffer_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;
40d6b753 122 fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
d6d3f033
RX
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);
40d6b753 149 values = (gcov_type *) xmalloc (len);
d6d3f033
RX
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
164fail:
d273c40a 165 gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
d6d3f033
RX
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
be9d9fdb
ML
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
175static char *
176gcov_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
d6d3f033
RX
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
197static int
198gcov_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];
e3a682f4 204 char ver_string[128], expected_string[128];
d6d3f033
RX
205
206 GCOV_UNSIGNED2STRING (v, version);
207 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
208
d273c40a 209 gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
be9d9fdb
ML
210 "got %s (%.4s)\n",
211 filename? filename : ptr->filename,
212 gcov_version_string (expected_string, e), e,
e3a682f4 213 gcov_version_string (ver_string, v), v);
d6d3f033
RX
214 return 0;
215 }
216 return 1;
217}
218
d6d3f033
RX
219/* buffer for the fn_data from another program. */
220static struct gcov_fn_buffer *fn_buffer;
d6d3f033 221
d6d3f033
RX
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
229static int
19926161
NS
230merge_one_data (const char *filename,
231 struct gcov_info *gi_ptr,
512cc015 232 struct gcov_summary *summary)
d6d3f033
RX
233{
234 gcov_unsigned_t tag, length;
235 unsigned t_ix;
512cc015 236 int f_ix = -1;
d6d3f033
RX
237 int error = 0;
238 struct gcov_fn_buffer **fn_tail = &fn_buffer;
d6d3f033
RX
239
240 length = gcov_read_unsigned ();
6dc33097 241 if (!gcov_version (gi_ptr, length, filename))
d6d3f033
RX
242 return -1;
243
244 length = gcov_read_unsigned ();
245 if (length != gi_ptr->stamp)
0e8f29da
ML
246 {
247 /* Read from a different compilation. Overwrite the file. */
d273c40a 248 gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
0e8f29da
ML
249 "with a different timestamp\n", filename);
250 return 0;
251 }
d6d3f033 252
512cc015
ML
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);
d6d3f033 259
512cc015 260 tag = gcov_read_unsigned ();
d6d3f033
RX
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. */
6dc33097 287 fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
d6d3f033
RX
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
871e5ada 313 tag = gcov_read_unsigned ();
ece21ff6
ML
314 int read_length = (int)gcov_read_unsigned ();
315 length = abs (read_length);
871e5ada
ML
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;
ece21ff6
ML
321 /* Merging with all zero counters does not make sense. */
322 if (read_length > 0)
323 (*merge) (ci_ptr->values, ci_ptr->num);
871e5ada
ML
324 ci_ptr++;
325 }
d6d3f033 326 if ((error = gcov_is_error ()))
871e5ada 327 goto read_error;
d6d3f033
RX
328 }
329
330 if (tag)
331 {
332 read_mismatch:;
d273c40a 333 gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
6dc33097 334 filename, f_ix >= 0 ? "function" : "summary",
d6d3f033
RX
335 f_ix < 0 ? -1 - f_ix : f_ix);
336 return -1;
337 }
338 return 0;
339
340read_error:
d273c40a 341 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
d6d3f033
RX
342 error < 0 ? "Overflow": "Error");
343 return -1;
344}
345
6a8fc0c3
ML
346#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
347
871e5ada
ML
348/* Store all TOP N counters where each has a dynamic length. */
349
350static void
6a8fc0c3
ML
351write_topn_counters (const struct gcov_ctr_info *ci_ptr,
352 unsigned t_ix,
353 gcov_unsigned_t n_counts)
871e5ada
ML
354{
355 unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
356 gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
6a8fc0c3
ML
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));
871e5ada 379 unsigned pair_total = 0;
6a8fc0c3 380
871e5ada 381 for (unsigned i = 0; i < counters; i++)
6a8fc0c3
ML
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
871e5ada
ML
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 {
871e5ada 398 gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
6a8fc0c3 399 gcov_write_counter (list_sizes[i]);
862b9b22 400 gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
6a8fc0c3
ML
401
402 unsigned j = 0;
862b9b22 403 for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
6a8fc0c3 404 j < list_sizes[i]; node = node->next, j++)
871e5ada
ML
405 {
406 gcov_write_counter (node->value);
407 gcov_write_counter (node->count);
408 }
409 }
410}
411
d6d3f033
RX
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
416static void
19926161 417write_one_data (const struct gcov_info *gi_ptr,
512cc015 418 const struct gcov_summary *prg_p)
d6d3f033
RX
419{
420 unsigned f_ix;
d6d3f033 421
512cc015
ML
422 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
423 gcov_write_unsigned (gi_ptr->stamp);
d6d3f033
RX
424
425 /* Generate whole program statistics. */
512cc015 426 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
d6d3f033
RX
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 {
ece21ff6 464 gcov_position_t n_counts;
d6d3f033 465
ece21ff6
ML
466 if (!gi_ptr->merge[t_ix])
467 continue;
d6d3f033 468
ece21ff6 469 n_counts = ci_ptr->num;
871e5ada 470
4ecf368f 471 if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
6a8fc0c3 472 write_topn_counters (ci_ptr, t_ix, n_counts);
871e5ada
ML
473 else
474 {
ece21ff6
ML
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 }
871e5ada
ML
494 }
495
ece21ff6
ML
496 ci_ptr++;
497 }
d6d3f033
RX
498 if (buffered)
499 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
500 }
501
502 gcov_write_unsigned (0);
503}
504
d6d3f033
RX
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
512static void
19926161 513dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
88891c5f
ML
514 unsigned run_counted ATTRIBUTE_UNUSED,
515 gcov_type run_max ATTRIBUTE_UNUSED)
d6d3f033 516{
512cc015 517 struct gcov_summary summary = {};
d6d3f033
RX
518 int error;
519 gcov_unsigned_t tag;
d6d3f033 520 fn_buffer = 0;
d6d3f033
RX
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 {
d273c40a
ML
532 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
533 gf->filename);
d6d3f033
RX
534 goto read_fatal;
535 }
512cc015 536 error = merge_one_data (gf->filename, gi_ptr, &summary);
d6d3f033
RX
537 if (error == -1)
538 goto read_fatal;
539 }
540
541 gcov_rewrite ();
542
88891c5f
ML
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
d6d3f033 552
512cc015 553 write_one_data (gi_ptr, &summary);
d6d3f033
RX
554 /* fall through */
555
556read_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 ?
d273c40a
ML
562 GCOV_PROF_PREFIX "Overflow writing\n" :
563 GCOV_PROF_PREFIX "Error writing\n",
6dc33097 564 gf->filename);
d6d3f033
RX
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
4303c581
NS
572#if !IN_GCOV_TOOL
573static
574#endif
575void
19926161 576gcov_do_dump (struct gcov_info *list, int run_counted)
d6d3f033
RX
577{
578 struct gcov_info *gi_ptr;
6dc33097 579 struct gcov_filename gf;
d6d3f033 580
512cc015
ML
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 }
d6d3f033
RX
593
594 allocate_filename_struct (&gf);
595
596 /* Now merge each file. */
19926161 597 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
6c086e8c 598 {
512cc015 599 dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
6c086e8c
ML
600 free (gf.filename);
601 }
d6d3f033 602
6c086e8c 603 free (gf.prefix);
d6d3f033
RX
604}
605
63971184
ML
606#if IN_GCOV_TOOL
607const char *
608__attribute__ ((unused))
609gcov_get_filename (struct gcov_info *list)
610{
611 return list->filename;
612}
613#endif
614
b98a872b 615#if !IN_GCOV_TOOL
19926161 616void
4303c581 617__gcov_dump_one (struct gcov_root *root)
19926161 618{
4303c581 619 if (root->dumped)
19926161
NS
620 return;
621
4303c581 622 gcov_do_dump (root->list, root->run_counted);
19926161 623
4303c581
NS
624 root->dumped = 1;
625 root->run_counted = 1;
19926161
NS
626}
627
cadb2b96 628/* Per-dynamic-object gcov state. */
4303c581 629struct gcov_root __gcov_root;
d6d3f033 630
cadb2b96
NS
631/* Exactly one of these will be live in the process image. */
632struct gcov_master __gcov_master =
633 {GCOV_VERSION, 0};
bc2b1a23 634
00d79dc4
ML
635/* Dynamic pool for gcov_kvp structures. */
636struct gcov_kvp *__gcov_kvp_dynamic_pool;
bc2b1a23 637
00d79dc4
ML
638/* Index into __gcov_kvp_dynamic_pool array. */
639unsigned __gcov_kvp_dynamic_pool_index;
640
641/* Size of _gcov_kvp_dynamic_pool array. */
642unsigned __gcov_kvp_dynamic_pool_size;
cadb2b96 643
8c9434c2
ML
644void
645__gcov_exit (void)
d6d3f033 646{
4303c581 647 __gcov_dump_one (&__gcov_root);
cadb2b96
NS
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;
8aa5bdd6
AC
654
655 gcov_error_exit ();
d6d3f033
RX
656}
657
658/* Add a new object file onto the bb chain. Invoked automatically
659 when running an object file's global ctors. */
660
661void
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 {
4303c581 668 if (!__gcov_root.list)
cadb2b96
NS
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 }
cadb2b96 678 }
d6d3f033 679
4303c581
NS
680 info->next = __gcov_root.list;
681 __gcov_root.list = info;
d6d3f033 682 }
d6d3f033 683}
b98a872b 684#endif /* !IN_GCOV_TOOL */
d6d3f033
RX
685#endif /* L_gcov */
686#endif /* inhibit_libc */