]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov.c
Workaround binutils PR14342
[thirdparty/gcc.git] / libgcc / libgcov.c
CommitLineData
23af32e6
NS
1/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
5d5bf775 3/* Copyright (C) 1989-2013 Free Software Foundation, Inc.
23af32e6
NS
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
748086b7 9Software Foundation; either version 3, or (at your option) any later
23af32e6
NS
10version.
11
23af32e6
NS
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
748086b7
JJ
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/>. */
23af32e6 25
23af32e6
NS
26#include "tconfig.h"
27#include "tsystem.h"
28#include "coretypes.h"
29#include "tm.h"
852b75ed 30#include "libgcc_tm.h"
33e3e24d 31#include "gthr.h"
23af32e6 32
474f141e
NS
33#if defined(inhibit_libc)
34#define IN_LIBGCOV (-1)
35#else
474f141e
NS
36#define IN_LIBGCOV 1
37#if defined(L_gcov)
38#define GCOV_LINKAGE /* nothing */
39#endif
40#endif
41#include "gcov-io.h"
42
43#if defined(inhibit_libc)
44/* If libc and its header files are not available, provide dummy functions. */
45
46#ifdef L_gcov
47void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
48void __gcov_flush (void) {}
49#endif
50
4e8ee9cb
TJ
51#ifdef L_gcov_reset
52void __gcov_reset (void) {}
53#endif
54
55#ifdef L_gcov_dump
56void __gcov_dump (void) {}
57#endif
58
474f141e
NS
59#ifdef L_gcov_merge_add
60void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
61 unsigned n_counters __attribute__ ((unused))) {}
62#endif
63
af166e5d
ZD
64#ifdef L_gcov_merge_single
65void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
66 unsigned n_counters __attribute__ ((unused))) {}
67#endif
68
69#ifdef L_gcov_merge_delta
70void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
71 unsigned n_counters __attribute__ ((unused))) {}
72#endif
73
474f141e 74#else
23af32e6 75
23af32e6 76#include <string.h>
474f141e 77#if GCOV_LOCKED
23af32e6
NS
78#include <fcntl.h>
79#include <errno.h>
c2cd64b5 80#include <sys/stat.h>
23af32e6 81#endif
09780dfb 82
4e8ee9cb
TJ
83extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
84extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
85extern int gcov_dump_complete ATTRIBUTE_HIDDEN;
86
09780dfb 87#ifdef L_gcov
ca29da43 88#include "gcov-io.c"
23af32e6 89
5366b186
NS
90struct gcov_fn_buffer
91{
92 struct gcov_fn_buffer *next;
93 unsigned fn_ix;
94 struct gcov_fn_info info;
95 /* note gcov_fn_info ends in a trailing array. */
96};
97
9f71de84
TJ
98struct gcov_summary_buffer
99{
100 struct gcov_summary_buffer *next;
101 struct gcov_summary summary;
102};
103
23af32e6
NS
104/* Chain of per-object gcov structures. */
105static struct gcov_info *gcov_list;
106
992f396f
GZ
107/* Size of the longest file name. */
108static size_t gcov_max_filename = 0;
109
4e8ee9cb
TJ
110/* Flag when the profile has already been dumped via __gcov_dump(). */
111int gcov_dump_complete = 0;
112
b8698a0f
L
113/* Make sure path component of the given FILENAME exists, create
114 missing directories. FILENAME must be writable.
992f396f
GZ
115 Returns zero on success, or -1 if an error occurred. */
116
160e2e4f 117static int
992f396f
GZ
118create_file_directory (char *filename)
119{
78e7dd6a
KT
120#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
121 (void) filename;
122 return -1;
123#else
992f396f
GZ
124 char *s;
125
78e7dd6a
KT
126 s = filename;
127
128 if (HAS_DRIVE_SPEC(s))
129 s += 2;
130 if (IS_DIR_SEPARATOR(*s))
131 ++s;
132 for (; *s != '\0'; s++)
992f396f
GZ
133 if (IS_DIR_SEPARATOR(*s))
134 {
135 char sep = *s;
136 *s = '\0';
137
138 /* Try to make directory if it doesn't already exist. */
139 if (access (filename, F_OK) == -1
78e7dd6a 140#ifdef TARGET_POSIX_IO
992f396f 141 && mkdir (filename, 0755) == -1
78e7dd6a
KT
142#else
143 && mkdir (filename) == -1
144#endif
992f396f
GZ
145 /* The directory might have been made by another process. */
146 && errno != EEXIST)
147 {
148 fprintf (stderr, "profiling:%s:Cannot create directory\n",
149 filename);
150 *s = sep;
151 return -1;
152 };
b8698a0f 153
992f396f
GZ
154 *s = sep;
155 };
156 return 0;
4969c0d8 157#endif
78e7dd6a 158}
992f396f 159
04dbc287
NS
160static struct gcov_fn_buffer *
161free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
162 unsigned limit)
163{
164 struct gcov_fn_buffer *next;
165 unsigned ix, n_ctr = 0;
166
167 if (!buffer)
168 return 0;
169 next = buffer->next;
170
171 for (ix = 0; ix != limit; ix++)
172 if (gi_ptr->merge[ix])
173 free (buffer->info.ctrs[n_ctr++].values);
174 free (buffer);
175 return next;
176}
177
5366b186 178static struct gcov_fn_buffer **
04dbc287
NS
179buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
180 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
5366b186 181{
04dbc287 182 unsigned n_ctrs = 0, ix = 0;
5366b186 183 struct gcov_fn_buffer *fn_buffer;
04dbc287 184 unsigned len;
5366b186
NS
185
186 for (ix = GCOV_COUNTERS; ix--;)
187 if (gi_ptr->merge[ix])
188 n_ctrs++;
189
04dbc287
NS
190 len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
191 fn_buffer = (struct gcov_fn_buffer *)malloc (len);
5366b186
NS
192
193 if (!fn_buffer)
04dbc287 194 goto fail;
5366b186
NS
195
196 fn_buffer->next = 0;
197 fn_buffer->fn_ix = fn_ix;
198 fn_buffer->info.ident = gcov_read_unsigned ();
199 fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
200 fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
201
202 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
203 {
204 gcov_unsigned_t length;
205 gcov_type *values;
206
207 if (!gi_ptr->merge[ix])
208 continue;
209
210 if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
5366b186 211 {
04dbc287 212 len = 0;
5366b186
NS
213 goto fail;
214 }
04dbc287
NS
215
216 length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
217 len = length * sizeof (gcov_type);
218 values = (gcov_type *)malloc (len);
219 if (!values)
220 goto fail;
221
5366b186
NS
222 fn_buffer->info.ctrs[n_ctrs].num = length;
223 fn_buffer->info.ctrs[n_ctrs].values = values;
224
225 while (length--)
226 *values++ = gcov_read_counter ();
227 n_ctrs++;
228 }
229
230 *end_ptr = fn_buffer;
231 return &fn_buffer->next;
232
233 fail:
04dbc287
NS
234 fprintf (stderr, "profiling:%s:Function %u %s %u \n", filename, fn_ix,
235 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
236
237 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
238}
239
240/* Add an unsigned value to the current crc */
241
242static gcov_unsigned_t
243crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
244{
245 unsigned ix;
246
247 for (ix = 32; ix--; value <<= 1)
248 {
249 unsigned feedback;
250
251 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
252 crc32 <<= 1;
253 crc32 ^= feedback;
254 }
255
256 return crc32;
5366b186
NS
257}
258
992f396f
GZ
259/* Check if VERSION of the info block PTR matches libgcov one.
260 Return 1 on success, or zero in case of versions mismatch.
b8698a0f 261 If FILENAME is not NULL, its value used for reporting purposes
992f396f 262 instead of value from the info block. */
b8698a0f 263
992f396f
GZ
264static int
265gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
266 const char *filename)
23af32e6 267{
160e2e4f 268 if (version != GCOV_VERSION)
23af32e6 269 {
330d2e2a
NS
270 char v[4], e[4];
271
272 GCOV_UNSIGNED2STRING (v, version);
273 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
b8698a0f 274
160e2e4f
NS
275 fprintf (stderr,
276 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
992f396f 277 filename? filename : ptr->filename, e, v);
160e2e4f 278 return 0;
23af32e6 279 }
160e2e4f 280 return 1;
23af32e6
NS
281}
282
9f71de84
TJ
283/* Insert counter VALUE into HISTOGRAM. */
284
285static void
286gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
287{
288 unsigned i;
289
290 i = gcov_histo_index(value);
291 histogram[i].num_counters++;
292 histogram[i].cum_value += value;
293 if (value < histogram[i].min_value)
294 histogram[i].min_value = value;
295}
296
297/* Computes a histogram of the arc counters to place in the summary SUM. */
298
299static void
300gcov_compute_histogram (struct gcov_summary *sum)
301{
302 struct gcov_info *gi_ptr;
303 const struct gcov_fn_info *gfi_ptr;
304 const struct gcov_ctr_info *ci_ptr;
305 struct gcov_ctr_summary *cs_ptr;
306 unsigned t_ix, f_ix, ctr_info_ix, ix;
307 int h_ix;
308
309 /* This currently only applies to arc counters. */
310 t_ix = GCOV_COUNTER_ARCS;
311
312 /* First check if there are any counts recorded for this counter. */
313 cs_ptr = &(sum->ctrs[t_ix]);
314 if (!cs_ptr->num)
315 return;
316
317 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
318 {
319 cs_ptr->histogram[h_ix].num_counters = 0;
320 cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max;
321 cs_ptr->histogram[h_ix].cum_value = 0;
322 }
323
324 /* Walk through all the per-object structures and record each of
325 the count values in histogram. */
326 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
327 {
328 if (!gi_ptr->merge[t_ix])
329 continue;
330
331 /* Find the appropriate index into the gcov_ctr_info array
332 for the counter we are currently working on based on the
333 existence of the merge function pointer for this object. */
334 for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++)
335 {
336 if (gi_ptr->merge[ix])
337 ctr_info_ix++;
338 }
339 for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
340 {
341 gfi_ptr = gi_ptr->functions[f_ix];
342
343 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
344 continue;
345
346 ci_ptr = &gfi_ptr->ctrs[ctr_info_ix];
347 for (ix = 0; ix < ci_ptr->num; ix++)
348 gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]);
349 }
350 }
351}
352
23af32e6
NS
353/* Dump the coverage counts. We merge with existing counts when
354 possible, to avoid growing the .da files ad infinitum. We use this
355 program's checksum to make sure we only accumulate whole program
356 statistics to the correct summary. An object file might be embedded
357 in two separate programs, and we must keep the two program
358 summaries separate. */
359
4e8ee9cb 360void
23af32e6
NS
361gcov_exit (void)
362{
cdb23767 363 struct gcov_info *gi_ptr;
5366b186
NS
364 const struct gcov_fn_info *gfi_ptr;
365 struct gcov_summary this_prg; /* summary for program. */
822a258a 366#if !GCOV_LOCKED
5366b186 367 struct gcov_summary all_prg; /* summary for all instances of program. */
822a258a 368#endif
50612a04
ZD
369 struct gcov_ctr_summary *cs_ptr;
370 const struct gcov_ctr_info *ci_ptr;
04dbc287
NS
371 unsigned t_ix;
372 int f_ix;
50612a04 373 gcov_unsigned_t c_num;
992f396f
GZ
374 const char *gcov_prefix;
375 int gcov_prefix_strip = 0;
376 size_t prefix_length;
377 char *gi_filename, *gi_filename_up;
04dbc287 378 gcov_unsigned_t crc32 = 0;
cdb23767 379
4e8ee9cb
TJ
380 /* Prevent the counters from being dumped a second time on exit when the
381 application already wrote out the profile using __gcov_dump(). */
382 if (gcov_dump_complete)
383 return;
384
822a258a 385#if !GCOV_LOCKED
5366b186 386 memset (&all_prg, 0, sizeof (all_prg));
822a258a 387#endif
cdb23767 388 /* Find the totals for this execution. */
5366b186 389 memset (&this_prg, 0, sizeof (this_prg));
cdb23767 390 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
04dbc287
NS
391 {
392 crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
393 crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
394
395 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
396 {
397 gfi_ptr = gi_ptr->functions[f_ix];
50612a04 398
04dbc287
NS
399 if (gfi_ptr && gfi_ptr->key != gi_ptr)
400 gfi_ptr = 0;
401
402 crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
403 crc32 = crc32_unsigned (crc32,
404 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
405 if (!gfi_ptr)
406 continue;
407
408 ci_ptr = gfi_ptr->ctrs;
409 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
410 {
411 if (!gi_ptr->merge[t_ix])
412 continue;
413
414 cs_ptr = &this_prg.ctrs[t_ix];
415 cs_ptr->num += ci_ptr->num;
416 crc32 = crc32_unsigned (crc32, ci_ptr->num);
417
418 for (c_num = 0; c_num < ci_ptr->num; c_num++)
419 {
420 cs_ptr->sum_all += ci_ptr->values[c_num];
421 if (cs_ptr->run_max < ci_ptr->values[c_num])
422 cs_ptr->run_max = ci_ptr->values[c_num];
423 }
424 ci_ptr++;
425 }
426 }
427 }
9f71de84 428 gcov_compute_histogram (&this_prg);
cdb23767 429
78e7dd6a
KT
430 {
431 /* Check if the level of dirs to strip off specified. */
432 char *tmp = getenv("GCOV_PREFIX_STRIP");
433 if (tmp)
434 {
435 gcov_prefix_strip = atoi (tmp);
436 /* Do not consider negative values. */
437 if (gcov_prefix_strip < 0)
438 gcov_prefix_strip = 0;
439 }
440 }
5366b186 441
992f396f
GZ
442 /* Get file name relocation prefix. Non-absolute values are ignored. */
443 gcov_prefix = getenv("GCOV_PREFIX");
78e7dd6a 444 if (gcov_prefix)
992f396f 445 {
992f396f
GZ
446 prefix_length = strlen(gcov_prefix);
447
9d6aab7e 448 /* Remove an unnecessary trailing '/' */
992f396f
GZ
449 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
450 prefix_length--;
451 }
3ca48b3e
L
452 else
453 prefix_length = 0;
b8698a0f 454
78e7dd6a
KT
455 /* If no prefix was specified and a prefix stip, then we assume
456 relative. */
457 if (gcov_prefix_strip != 0 && prefix_length == 0)
458 {
459 gcov_prefix = ".";
460 prefix_length = 1;
461 }
462 /* Allocate and initialize the filename scratch space plus one. */
463 gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 2);
992f396f
GZ
464 if (prefix_length)
465 memcpy (gi_filename, gcov_prefix, prefix_length);
466 gi_filename_up = gi_filename + prefix_length;
b8698a0f 467
f9da5064 468 /* Now merge each file. */
cdb23767 469 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
23af32e6 470 {
5366b186
NS
471 unsigned n_counts;
472 struct gcov_summary prg; /* summary for this object over all
473 program. */
822a258a
TJ
474 struct gcov_ctr_summary *cs_prg, *cs_tprg;
475#if !GCOV_LOCKED
476 struct gcov_ctr_summary *cs_all;
477#endif
7d63a2fa 478 int error = 0;
9b514d25 479 gcov_unsigned_t tag, length;
7d63a2fa 480 gcov_position_t summary_pos = 0;
00cf2913 481 gcov_position_t eof_pos = 0;
78e7dd6a 482 const char *fname, *s;
5366b186
NS
483 struct gcov_fn_buffer *fn_buffer = 0;
484 struct gcov_fn_buffer **fn_tail = &fn_buffer;
9f71de84
TJ
485 struct gcov_summary_buffer *next_sum_buffer, *sum_buffer = 0;
486 struct gcov_summary_buffer **sum_tail = &sum_buffer;
78e7dd6a
KT
487
488 fname = gi_ptr->filename;
cdb23767 489
78e7dd6a
KT
490 /* Avoid to add multiple drive letters into combined path. */
491 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
492 fname += 2;
493
b8698a0f 494 /* Build relocated filename, stripping off leading
992f396f
GZ
495 directories from the initial filename if requested. */
496 if (gcov_prefix_strip > 0)
497 {
498 int level = 0;
78e7dd6a
KT
499 s = fname;
500 if (IS_DIR_SEPARATOR(*s))
501 ++s;
992f396f
GZ
502
503 /* Skip selected directory levels. */
78e7dd6a 504 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
992f396f
GZ
505 if (IS_DIR_SEPARATOR(*s))
506 {
507 fname = s;
508 level++;
78e7dd6a 509 }
992f396f 510 }
5366b186 511
78e7dd6a 512 /* Update complete filename with stripped original. */
9f47a24e
MT
513 if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
514 {
515 /* If prefix is given, add directory separator. */
78e7dd6a
KT
516 strcpy (gi_filename_up, "/");
517 strcpy (gi_filename_up + 1, fname);
518 }
992f396f 519 else
78e7dd6a 520 strcpy (gi_filename_up, fname);
992f396f 521
992f396f 522 if (!gcov_open (gi_filename))
23af32e6 523 {
992f396f
GZ
524 /* Open failed likely due to missed directory.
525 Create directory and retry to open file. */
526 if (create_file_directory (gi_filename))
527 {
528 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
529 continue;
530 }
531 if (!gcov_open (gi_filename))
532 {
533 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
534 continue;
535 }
23af32e6 536 }
160e2e4f
NS
537
538 tag = gcov_read_unsigned ();
539 if (tag)
23af32e6
NS
540 {
541 /* Merge data from file. */
160e2e4f 542 if (tag != GCOV_DATA_MAGIC)
23af32e6
NS
543 {
544 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
992f396f 545 gi_filename);
00cf2913 546 goto read_fatal;
23af32e6 547 }
94de45d9 548 length = gcov_read_unsigned ();
992f396f 549 if (!gcov_version (gi_ptr, length, gi_filename))
160e2e4f 550 goto read_fatal;
dd486eb2
NS
551
552 length = gcov_read_unsigned ();
553 if (length != gi_ptr->stamp)
00cf2913
NS
554 /* Read from a different compilation. Overwrite the file. */
555 goto rewrite;
b8698a0f 556
5366b186 557 /* Look for program summary. */
04dbc287 558 for (f_ix = 0;;)
23af32e6 559 {
5366b186
NS
560 struct gcov_summary tmp;
561
562 eof_pos = gcov_position ();
94de45d9 563 tag = gcov_read_unsigned ();
5366b186
NS
564 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
565 break;
566
04dbc287 567 f_ix--;
5366b186 568 length = gcov_read_unsigned ();
5366b186
NS
569 gcov_read_summary (&tmp);
570 if ((error = gcov_is_error ()))
571 goto read_error;
9f71de84
TJ
572 if (summary_pos)
573 {
574 /* Save all summaries after the one that will be
575 merged into below. These will need to be rewritten
576 as histogram merging may change the number of non-zero
577 histogram entries that will be emitted, and thus the
578 size of the merged summary. */
579 (*sum_tail) = (struct gcov_summary_buffer *)
580 malloc (sizeof(struct gcov_summary_buffer));
581 (*sum_tail)->summary = tmp;
582 (*sum_tail)->next = 0;
583 sum_tail = &((*sum_tail)->next);
584 goto next_summary;
585 }
586 if (tmp.checksum != crc32)
587 goto next_summary;
04dbc287
NS
588
589 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
590 if (tmp.ctrs[t_ix].num != this_prg.ctrs[t_ix].num)
9f71de84 591 goto next_summary;
04dbc287
NS
592 prg = tmp;
593 summary_pos = eof_pos;
594
595 next_summary:;
5366b186
NS
596 }
597
598 /* Merge execution counts for each function. */
04dbc287 599 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
5366b186
NS
600 f_ix++, tag = gcov_read_unsigned ())
601 {
602 gfi_ptr = gi_ptr->functions[f_ix];
603
604 if (tag != GCOV_TAG_FUNCTION)
605 goto read_mismatch;
23af32e6 606
04dbc287 607 length = gcov_read_unsigned ();
5366b186
NS
608 if (!length)
609 /* This function did not appear in the other program.
610 We have nothing to merge. */
611 continue;
612
613 if (length != GCOV_TAG_FUNCTION_LENGTH)
614 goto read_mismatch;
615
616 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
23af32e6 617 {
5366b186
NS
618 /* This function appears in the other program. We
619 need to buffer the information in order to write
620 it back out -- we'll be inserting data before
621 this point, so cannot simply keep the data in the
622 file. */
04dbc287
NS
623 fn_tail = buffer_fn_data (gi_filename,
624 gi_ptr, fn_tail, f_ix);
5366b186
NS
625 if (!fn_tail)
626 goto read_mismatch;
627 continue;
23af32e6 628 }
cb9e4555 629
04dbc287
NS
630 length = gcov_read_unsigned ();
631 if (length != gfi_ptr->ident)
632 goto read_mismatch;
633
634 length = gcov_read_unsigned ();
635 if (length != gfi_ptr->lineno_checksum)
636 goto read_mismatch;
637
638 length = gcov_read_unsigned ();
639 if (length != gfi_ptr->cfg_checksum)
5366b186
NS
640 goto read_mismatch;
641
642 ci_ptr = gfi_ptr->ctrs;
50612a04
ZD
643 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
644 {
5366b186 645 gcov_merge_fn merge = gi_ptr->merge[t_ix];
50612a04 646
5366b186 647 if (!merge)
50612a04 648 continue;
b8698a0f 649
50612a04
ZD
650 tag = gcov_read_unsigned ();
651 length = gcov_read_unsigned ();
652 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
5366b186 653 || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
50612a04 654 goto read_mismatch;
5366b186
NS
655 (*merge) (ci_ptr->values, ci_ptr->num);
656 ci_ptr++;
cb9e4555 657 }
94de45d9
NS
658 if ((error = gcov_is_error ()))
659 goto read_error;
23af32e6
NS
660 }
661
5366b186 662 if (tag)
23af32e6 663 {
5366b186 664 read_mismatch:;
04dbc287
NS
665 fprintf (stderr, "profiling:%s:Merge mismatch for %s %u\n",
666 gi_filename, f_ix >= 0 ? "function" : "summary",
667 f_ix < 0 ? -1 - f_ix : f_ix);
5366b186 668 goto read_fatal;
23af32e6 669 }
23af32e6 670 }
00cf2913 671 goto rewrite;
b8698a0f 672
00cf2913 673 read_error:;
5366b186
NS
674 fprintf (stderr, "profiling:%s:%s merging\n", gi_filename,
675 error < 0 ? "Overflow": "Error");
b8698a0f 676
04dbc287 677 goto read_fatal;
00cf2913 678
160e2e4f
NS
679 rewrite:;
680 gcov_rewrite ();
7d63a2fa 681 if (!summary_pos)
5366b186
NS
682 {
683 memset (&prg, 0, sizeof (prg));
684 summary_pos = eof_pos;
685 }
23af32e6 686
cdb23767 687 /* Merge the summaries. */
50612a04 688 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
cdb23767 689 {
5366b186
NS
690 cs_prg = &prg.ctrs[t_ix];
691 cs_tprg = &this_prg.ctrs[t_ix];
50612a04 692
5366b186 693 if (gi_ptr->merge[t_ix])
cdb23767 694 {
cdb23767 695 if (!cs_prg->runs++)
9f71de84 696 cs_prg->num = cs_tprg->num;
cdb23767
NS
697 cs_prg->sum_all += cs_tprg->sum_all;
698 if (cs_prg->run_max < cs_tprg->run_max)
699 cs_prg->run_max = cs_tprg->run_max;
700 cs_prg->sum_max += cs_tprg->run_max;
9f71de84
TJ
701 if (cs_prg->runs == 1)
702 memcpy (cs_prg->histogram, cs_tprg->histogram,
703 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
704 else
705 gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram);
cdb23767 706 }
5366b186 707 else if (cs_prg->runs)
cdb23767 708 goto read_mismatch;
b8698a0f 709
822a258a
TJ
710#if !GCOV_LOCKED
711 cs_all = &all_prg.ctrs[t_ix];
cdb23767 712 if (!cs_all->runs && cs_prg->runs)
822a258a
TJ
713 {
714 cs_all->num = cs_prg->num;
715 cs_all->runs = cs_prg->runs;
716 cs_all->sum_all = cs_prg->sum_all;
717 cs_all->run_max = cs_prg->run_max;
718 cs_all->sum_max = cs_prg->sum_max;
719 }
5366b186 720 else if (!all_prg.checksum
c6c36e73
TJ
721 /* Don't compare the histograms, which may have slight
722 variations depending on the order they were updated
723 due to the truncating integer divides used in the
724 merge. */
822a258a
TJ
725 && (cs_all->num != cs_prg->num
726 || cs_all->runs != cs_prg->runs
727 || cs_all->sum_all != cs_prg->sum_all
728 || cs_all->run_max != cs_prg->run_max
729 || cs_all->sum_max != cs_prg->sum_max))
cdb23767 730 {
822a258a
TJ
731 fprintf (stderr,
732 "profiling:%s:Data file mismatch - some data files may "
733 "have been concurrently updated without locking support\n",
734 gi_filename);
5366b186 735 all_prg.checksum = ~0u;
cdb23767 736 }
822a258a 737#endif
cdb23767 738 }
b8698a0f 739
04dbc287 740 prg.checksum = crc32;
b8698a0f 741
23af32e6 742 /* Write out the data. */
5366b186
NS
743 if (!eof_pos)
744 {
745 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
746 gcov_write_unsigned (gi_ptr->stamp);
747 }
748
749 if (summary_pos)
750 gcov_seek (summary_pos);
751
752 /* Generate whole program statistics. */
753 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &prg);
754
9f71de84
TJ
755 /* Rewrite all the summaries that were after the summary we merged
756 into. This is necessary as the merged summary may have a different
757 size due to the number of non-zero histogram entries changing after
758 merging. */
759
760 while (sum_buffer)
761 {
762 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
763 next_sum_buffer = sum_buffer->next;
764 free (sum_buffer);
765 sum_buffer = next_sum_buffer;
766 }
b8698a0f 767
23af32e6 768 /* Write execution counts for each function. */
04dbc287 769 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
23af32e6 770 {
5366b186 771 unsigned buffered = 0;
50612a04 772
04dbc287 773 if (fn_buffer && fn_buffer->fn_ix == (unsigned)f_ix)
5366b186
NS
774 {
775 /* Buffered data from another program. */
776 buffered = 1;
777 gfi_ptr = &fn_buffer->info;
778 length = GCOV_TAG_FUNCTION_LENGTH;
779 }
780 else
781 {
782 gfi_ptr = gi_ptr->functions[f_ix];
783 if (gfi_ptr && gfi_ptr->key == gi_ptr)
784 length = GCOV_TAG_FUNCTION_LENGTH;
785 else
786 length = 0;
787 }
788
789 gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
790 if (!length)
791 continue;
792
793 gcov_write_unsigned (gfi_ptr->ident);
794 gcov_write_unsigned (gfi_ptr->lineno_checksum);
795 gcov_write_unsigned (gfi_ptr->cfg_checksum);
cb9e4555 796
5366b186 797 ci_ptr = gfi_ptr->ctrs;
50612a04
ZD
798 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
799 {
5366b186 800 if (!gi_ptr->merge[t_ix])
50612a04
ZD
801 continue;
802
5366b186 803 n_counts = ci_ptr->num;
50612a04
ZD
804 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
805 GCOV_TAG_COUNTER_LENGTH (n_counts));
5366b186 806 gcov_type *c_ptr = ci_ptr->values;
50612a04
ZD
807 while (n_counts--)
808 gcov_write_counter (*c_ptr++);
5366b186
NS
809 ci_ptr++;
810 }
811 if (buffered)
04dbc287 812 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
23af32e6
NS
813 }
814
5366b186 815 gcov_write_unsigned (0);
04dbc287
NS
816
817 read_fatal:;
818 while (fn_buffer)
819 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
820
cdb23767 821 if ((error = gcov_close ()))
cdb23767
NS
822 fprintf (stderr, error < 0 ?
823 "profiling:%s:Overflow writing\n" :
824 "profiling:%s:Error writing\n",
992f396f 825 gi_filename);
23af32e6 826 }
23af32e6
NS
827}
828
4e8ee9cb
TJ
829/* Reset all counters to zero. */
830
831void
832gcov_clear (void)
833{
834 const struct gcov_info *gi_ptr;
835
836 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
837 {
838 unsigned f_ix;
839
840 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
841 {
842 unsigned t_ix;
843 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
844
845 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
846 continue;
847 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
848 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
849 {
850 if (!gi_ptr->merge[t_ix])
851 continue;
852
853 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
854 ci_ptr++;
855 }
856 }
857 }
858}
859
23af32e6
NS
860/* Add a new object file onto the bb chain. Invoked automatically
861 when running an object file's global ctors. */
862
863void
864__gcov_init (struct gcov_info *info)
865{
2cd8b32c 866 if (!info->version || !info->n_functions)
23af32e6 867 return;
992f396f 868 if (gcov_version (info, info->version, 0))
23af32e6 869 {
04dbc287 870 size_t filename_length = strlen(info->filename);
992f396f
GZ
871
872 /* Refresh the longest file name information */
873 if (filename_length > gcov_max_filename)
874 gcov_max_filename = filename_length;
b8698a0f 875
23af32e6
NS
876 if (!gcov_list)
877 atexit (gcov_exit);
b8698a0f 878
23af32e6
NS
879 info->next = gcov_list;
880 gcov_list = info;
881 }
882 info->version = 0;
883}
884
33e3e24d
RG
885#ifdef __GTHREAD_MUTEX_INIT
886ATTRIBUTE_HIDDEN __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
887#define init_mx_once()
888#else
889__gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
890
891static void
892init_mx (void)
893{
b260a8c0 894 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
33e3e24d
RG
895}
896static void
897init_mx_once (void)
898{
899 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
900 __gthread_once (&once, init_mx);
901}
902#endif
903
23af32e6
NS
904/* Called before fork or exec - write out profile information gathered so
905 far and reset it to zero. This avoids duplication or loss of the
906 profile information gathered so far. */
907
908void
909__gcov_flush (void)
910{
33e3e24d
RG
911 init_mx_once ();
912 __gthread_mutex_lock (&__gcov_flush_mx);
913
23af32e6 914 gcov_exit ();
4e8ee9cb 915 gcov_clear ();
33e3e24d
RG
916
917 __gthread_mutex_unlock (&__gcov_flush_mx);
23af32e6 918}
01e60c33 919
09780dfb
ZD
920#endif /* L_gcov */
921
4e8ee9cb
TJ
922#ifdef L_gcov_reset
923
924/* Function that can be called from application to reset counters to zero,
925 in order to collect profile in region of interest. */
926
927void
928__gcov_reset (void)
929{
930 gcov_clear ();
931 /* Re-enable dumping to support collecting profile in multiple regions
932 of interest. */
933 gcov_dump_complete = 0;
934}
935
936#endif /* L_gcov_reset */
937
938#ifdef L_gcov_dump
939
940/* Function that can be called from application to write profile collected
941 so far, in order to collect profile in region of interest. */
942
943void
944__gcov_dump (void)
945{
946 gcov_exit ();
947 /* Prevent profile from being dumped a second time on application exit. */
948 gcov_dump_complete = 1;
949}
950
951#endif /* L_gcov_dump */
952
09780dfb
ZD
953#ifdef L_gcov_merge_add
954/* The profile merging function that just adds the counters. It is given
955 an array COUNTERS of N_COUNTERS old counters and it reads the same number
956 of counters from the gcov file. */
957void
9b514d25 958__gcov_merge_add (gcov_type *counters, unsigned n_counters)
09780dfb
ZD
959{
960 for (; n_counters; counters++, n_counters--)
961 *counters += gcov_read_counter ();
962}
963#endif /* L_gcov_merge_add */
964
079a182e
JH
965#ifdef L_gcov_merge_ior
966/* The profile merging function that just adds the counters. It is given
967 an array COUNTERS of N_COUNTERS old counters and it reads the same number
968 of counters from the gcov file. */
969void
970__gcov_merge_ior (gcov_type *counters, unsigned n_counters)
971{
972 for (; n_counters; counters++, n_counters--)
973 *counters |= gcov_read_counter ();
974}
975#endif
976
af166e5d 977#ifdef L_gcov_merge_single
330d2e2a
NS
978/* The profile merging function for choosing the most common value.
979 It is given an array COUNTERS of N_COUNTERS old counters and it
980 reads the same number of counters from the gcov file. The counters
981 are split into 3-tuples where the members of the tuple have
982 meanings:
b8698a0f 983
af166e5d
ZD
984 -- the stored candidate on the most common value of the measured entity
985 -- counter
986 -- total number of evaluations of the value */
987void
988__gcov_merge_single (gcov_type *counters, unsigned n_counters)
989{
990 unsigned i, n_measures;
991 gcov_type value, counter, all;
992
cccd217d 993 gcc_assert (!(n_counters % 3));
af166e5d
ZD
994 n_measures = n_counters / 3;
995 for (i = 0; i < n_measures; i++, counters += 3)
996 {
997 value = gcov_read_counter ();
998 counter = gcov_read_counter ();
999 all = gcov_read_counter ();
1000
1001 if (counters[0] == value)
1002 counters[1] += counter;
1003 else if (counter > counters[1])
1004 {
1005 counters[0] = value;
1006 counters[1] = counter - counters[1];
1007 }
1008 else
1009 counters[1] -= counter;
1010 counters[2] += all;
1011 }
1012}
1013#endif /* L_gcov_merge_single */
1014
1015#ifdef L_gcov_merge_delta
330d2e2a
NS
1016/* The profile merging function for choosing the most common
1017 difference between two consecutive evaluations of the value. It is
1018 given an array COUNTERS of N_COUNTERS old counters and it reads the
1019 same number of counters from the gcov file. The counters are split
1020 into 4-tuples where the members of the tuple have meanings:
b8698a0f 1021
af166e5d
ZD
1022 -- the last value of the measured entity
1023 -- the stored candidate on the most common difference
1024 -- counter
1025 -- total number of evaluations of the value */
1026void
1027__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
1028{
1029 unsigned i, n_measures;
0f900dfa 1030 gcov_type value, counter, all;
af166e5d 1031
cccd217d 1032 gcc_assert (!(n_counters % 4));
af166e5d
ZD
1033 n_measures = n_counters / 4;
1034 for (i = 0; i < n_measures; i++, counters += 4)
1035 {
0f900dfa 1036 /* last = */ gcov_read_counter ();
af166e5d
ZD
1037 value = gcov_read_counter ();
1038 counter = gcov_read_counter ();
1039 all = gcov_read_counter ();
1040
1041 if (counters[1] == value)
1042 counters[2] += counter;
1043 else if (counter > counters[2])
1044 {
1045 counters[1] = value;
1046 counters[2] = counter - counters[2];
1047 }
1048 else
1049 counters[2] -= counter;
1050 counters[3] += all;
1051 }
1052}
1053#endif /* L_gcov_merge_delta */
1054
9885da8e
ZD
1055#ifdef L_gcov_interval_profiler
1056/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
1057 corresponding counter in COUNTERS. If the VALUE is above or below
1058 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
1059 instead. */
1060
1061void
1062__gcov_interval_profiler (gcov_type *counters, gcov_type value,
1063 int start, unsigned steps)
1064{
1065 gcov_type delta = value - start;
1066 if (delta < 0)
1067 counters[steps + 1]++;
1068 else if (delta >= steps)
1069 counters[steps]++;
1070 else
1071 counters[delta]++;
1072}
1073#endif
1074
1075#ifdef L_gcov_pow2_profiler
1076/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
1077 COUNTERS[0] is incremented. */
1078
1079void
1080__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
1081{
1082 if (value & (value - 1))
1083 counters[0]++;
1084 else
1085 counters[1]++;
1086}
1087#endif
1088
9885da8e
ZD
1089/* Tries to determine the most common value among its inputs. Checks if the
1090 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
1091 is incremented. If this is not the case and COUNTERS[1] is not zero,
1092 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
1093 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
1094 function is called more than 50% of the time with one value, this value
1095 will be in COUNTERS[0] in the end.
1096
1097 In any case, COUNTERS[2] is incremented. */
1098
6bad2617
TB
1099static inline void
1100__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
9885da8e
ZD
1101{
1102 if (value == counters[0])
1103 counters[1]++;
1104 else if (counters[1] == 0)
1105 {
1106 counters[1] = 1;
1107 counters[0] = value;
1108 }
1109 else
1110 counters[1]--;
1111 counters[2]++;
1112}
6bad2617
TB
1113
1114#ifdef L_gcov_one_value_profiler
1115void
1116__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
1117{
1118 __gcov_one_value_profiler_body (counters, value);
1119}
1120#endif
1121
1122#ifdef L_gcov_indirect_call_profiler
748d71f3
JH
1123/* This function exist only for workaround of binutils bug 14342.
1124 Once this compatibility hack is obsolette, it can be removed. */
1125
1126/* By default, the C++ compiler will use function addresses in the
1127 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
1128 tells the compiler to use function descriptors instead. The value
1129 of this macro says how many words wide the descriptor is (normally 2),
1130 but it may be dependent on target flags. Since we do not have access
1131 to the target flags here we just check to see if it is set and use
1132 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
1133
1134 It is assumed that the address of a function descriptor may be treated
1135 as a pointer to a function. */
1136
1137#ifdef TARGET_VTABLE_USES_DESCRIPTORS
1138#define VTABLE_USES_DESCRIPTORS 1
1139#else
1140#define VTABLE_USES_DESCRIPTORS 0
1141#endif
1142
1143/* Tries to determine the most common value among its inputs. */
1144void
1145__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
1146 void* cur_func, void* callee_func)
1147{
1148 /* If the C++ virtual tables contain function descriptors then one
1149 function may have multiple descriptors and we need to dereference
1150 the descriptors to see if they point to the same function. */
1151 if (cur_func == callee_func
1152 || (VTABLE_USES_DESCRIPTORS && callee_func
1153 && *(void **) cur_func == *(void **) callee_func))
1154 __gcov_one_value_profiler_body (counter, value);
1155}
1156
1157#endif
1158#ifdef L_gcov_indirect_call_profiler_v2
7894073c 1159
2fa3d31b
JH
1160/* These two variables are used to actually track caller and callee. Keep
1161 them in TLS memory so races are not common (they are written to often).
1162 The variables are set directly by GCC instrumented code, so declaration
1163 here must match one in tree-profile.c */
1164
1165#ifdef HAVE_CC_TLS
1166__thread
1167#endif
1168void * __gcov_indirect_call_callee;
1169#ifdef HAVE_CC_TLS
1170__thread
1171#endif
1172gcov_type * __gcov_indirect_call_counters;
1173
7894073c
SE
1174/* By default, the C++ compiler will use function addresses in the
1175 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
1176 tells the compiler to use function descriptors instead. The value
1177 of this macro says how many words wide the descriptor is (normally 2),
1178 but it may be dependent on target flags. Since we do not have access
1179 to the target flags here we just check to see if it is set and use
1180 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
1181
1182 It is assumed that the address of a function descriptor may be treated
1183 as a pointer to a function. */
1184
1185#ifdef TARGET_VTABLE_USES_DESCRIPTORS
1186#define VTABLE_USES_DESCRIPTORS 1
1187#else
1188#define VTABLE_USES_DESCRIPTORS 0
1189#endif
1190
6bad2617
TB
1191/* Tries to determine the most common value among its inputs. */
1192void
2fa3d31b 1193__gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
6bad2617 1194{
81a39e89
SE
1195 /* If the C++ virtual tables contain function descriptors then one
1196 function may have multiple descriptors and we need to dereference
1197 the descriptors to see if they point to the same function. */
2fa3d31b
JH
1198 if (cur_func == __gcov_indirect_call_callee
1199 || (VTABLE_USES_DESCRIPTORS && __gcov_indirect_call_callee
1200 && *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
1201 __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value);
6bad2617 1202}
9885da8e
ZD
1203#endif
1204
079a182e
JH
1205#ifdef L_gcov_average_profiler
1206/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1207 to saturate up. */
1208
1209void
1210__gcov_average_profiler (gcov_type *counters, gcov_type value)
1211{
1212 counters[0] += value;
1213 counters[1] ++;
1214}
1215#endif
1216
1217#ifdef L_gcov_ior_profiler
efbb59b2 1218/* Bitwise-OR VALUE into COUNTER. */
079a182e
JH
1219
1220void
1221__gcov_ior_profiler (gcov_type *counters, gcov_type value)
1222{
1223 *counters |= value;
1224}
1225#endif
1226
d1c38823
ZD
1227#ifdef L_gcov_fork
1228/* A wrapper for the fork function. Flushes the accumulated profiling data, so
1229 that they are not counted twice. */
1230
1231pid_t
1232__gcov_fork (void)
1233{
33e3e24d
RG
1234 pid_t pid;
1235 extern __gthread_mutex_t __gcov_flush_mx;
d1c38823 1236 __gcov_flush ();
33e3e24d
RG
1237 pid = fork ();
1238 if (pid == 0)
1239 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
1240 return pid;
d1c38823
ZD
1241}
1242#endif
1243
1244#ifdef L_gcov_execl
1245/* A wrapper for the execl function. Flushes the accumulated profiling data, so
1246 that they are not lost. */
1247
1248int
cbb8dee3 1249__gcov_execl (const char *path, char *arg, ...)
d1c38823
ZD
1250{
1251 va_list ap, aq;
1252 unsigned i, length;
1253 char **args;
1254
1255 __gcov_flush ();
1256
1257 va_start (ap, arg);
1258 va_copy (aq, ap);
1259
1260 length = 2;
1261 while (va_arg (ap, char *))
1262 length++;
1263 va_end (ap);
1264
858904db 1265 args = (char **) alloca (length * sizeof (void *));
cbb8dee3 1266 args[0] = arg;
d1c38823
ZD
1267 for (i = 1; i < length; i++)
1268 args[i] = va_arg (aq, char *);
1269 va_end (aq);
1270
1271 return execv (path, args);
1272}
1273#endif
1274
1275#ifdef L_gcov_execlp
1276/* A wrapper for the execlp function. Flushes the accumulated profiling data, so
1277 that they are not lost. */
1278
1279int
cbb8dee3 1280__gcov_execlp (const char *path, char *arg, ...)
d1c38823
ZD
1281{
1282 va_list ap, aq;
1283 unsigned i, length;
1284 char **args;
1285
1286 __gcov_flush ();
1287
1288 va_start (ap, arg);
1289 va_copy (aq, ap);
1290
1291 length = 2;
1292 while (va_arg (ap, char *))
1293 length++;
1294 va_end (ap);
1295
858904db 1296 args = (char **) alloca (length * sizeof (void *));
cbb8dee3 1297 args[0] = arg;
d1c38823
ZD
1298 for (i = 1; i < length; i++)
1299 args[i] = va_arg (aq, char *);
1300 va_end (aq);
1301
1302 return execvp (path, args);
1303}
1304#endif
1305
1306#ifdef L_gcov_execle
1307/* A wrapper for the execle function. Flushes the accumulated profiling data, so
1308 that they are not lost. */
1309
1310int
cbb8dee3 1311__gcov_execle (const char *path, char *arg, ...)
d1c38823
ZD
1312{
1313 va_list ap, aq;
1314 unsigned i, length;
1315 char **args;
1316 char **envp;
1317
1318 __gcov_flush ();
1319
1320 va_start (ap, arg);
1321 va_copy (aq, ap);
1322
1323 length = 2;
1324 while (va_arg (ap, char *))
1325 length++;
1326 va_end (ap);
1327
858904db 1328 args = (char **) alloca (length * sizeof (void *));
cbb8dee3 1329 args[0] = arg;
d1c38823
ZD
1330 for (i = 1; i < length; i++)
1331 args[i] = va_arg (aq, char *);
1332 envp = va_arg (aq, char **);
1333 va_end (aq);
1334
1335 return execve (path, args, envp);
1336}
1337#endif
1338
1339#ifdef L_gcov_execv
1340/* A wrapper for the execv function. Flushes the accumulated profiling data, so
1341 that they are not lost. */
1342
1343int
1344__gcov_execv (const char *path, char *const argv[])
1345{
1346 __gcov_flush ();
1347 return execv (path, argv);
1348}
1349#endif
1350
1351#ifdef L_gcov_execvp
1352/* A wrapper for the execvp function. Flushes the accumulated profiling data, so
1353 that they are not lost. */
1354
1355int
1356__gcov_execvp (const char *path, char *const argv[])
1357{
1358 __gcov_flush ();
1359 return execvp (path, argv);
1360}
1361#endif
1362
1363#ifdef L_gcov_execve
1364/* A wrapper for the execve function. Flushes the accumulated profiling data, so
1365 that they are not lost. */
1366
1367int
1368__gcov_execve (const char *path, char *const argv[], char *const envp[])
1369{
1370 __gcov_flush ();
1371 return execve (path, argv, envp);
1372}
1373#endif
01e60c33 1374#endif /* inhibit_libc */