1/* Routines required for instrumenting a program. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 4 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13In addition to the permissions in the GNU General Public License, the 14Free Software Foundation gives you unlimited permission to link the 15compiled version of this file into combinations with other programs, 16and to distribute those combinations without any restriction coming 17from the use of this file. (The General Public License restrictions 18do apply in other respects; for example, they cover modification of 19the file, and distribution when not linked into a combine 20executable.) 21 22GCC is distributed in the hope that it will be useful, but WITHOUT ANY 23WARRANTY; without even the implied warranty of MERCHANTABILITY or 24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25for more details. 26 27You should have received a copy of the GNU General Public License 28along with GCC; see the file COPYING. If not, write to the Free 29Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 3002110-1301, USA. */ 31 32#include "tconfig.h" 33#include "tsystem.h" 34#include "coretypes.h" 35#include "tm.h" 36 37#if defined(inhibit_libc) 38#define IN_LIBGCOV (-1) 39#else 40#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ 41#include <stdio.h> 42#define IN_LIBGCOV 1 43#if defined(L_gcov) 44#define GCOV_LINKAGE /* nothing */ 45#endif 46#endif 47#include "gcov-io.h" 48 49#if defined(inhibit_libc) 50/* If libc and its header files are not available, provide dummy functions. */ 51 52#ifdef L_gcov 53void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} 54void __gcov_flush (void) {} 55#endif 56 57#ifdef L_gcov_merge_add 58void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), 59 unsigned n_counters __attribute__ ((unused))) {} 60#endif 61 62#ifdef L_gcov_merge_single 63void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), 64 unsigned n_counters __attribute__ ((unused))) {} 65#endif 66 67#ifdef L_gcov_merge_delta 68void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)), 69 unsigned n_counters __attribute__ ((unused))) {} 70#endif 71 72#else 73 74#include <string.h> 75#if GCOV_LOCKED 76#include <fcntl.h> 77#include <errno.h> 78#include <sys/stat.h> 79#endif 80 81#ifdef L_gcov 82#include "gcov-io.c" 83 84/* Chain of per-object gcov structures. */ 85static struct gcov_info *gcov_list; 86 87/* A program checksum allows us to distinguish program data for an 88 object file included in multiple programs. */ 89static gcov_unsigned_t gcov_crc32; 90 91/* Size of the longest file name. */ 92static size_t gcov_max_filename = 0; 93 94#ifdef TARGET_POSIX_IO 95/* Make sure path component of the given FILENAME exists, create 96 missing directories. FILENAME must be writable. 97 Returns zero on success, or -1 if an error occurred. */ 98 99static int 100create_file_directory (char *filename) 101{ 102 char *s; 103 104 for (s = filename + 1; *s != '\0'; s++) 105 if (IS_DIR_SEPARATOR(*s)) 106 { 107 char sep = *s; 108 *s = '\0'; 109 110 /* Try to make directory if it doesn't already exist. */ 111 if (access (filename, F_OK) == -1 112 && mkdir (filename, 0755) == -1 113 /* The directory might have been made by another process. */ 114 && errno != EEXIST) 115 { 116 fprintf (stderr, "profiling:%s:Cannot create directory\n", 117 filename); 118 *s = sep; 119 return -1; 120 }; 121 122 *s = sep; 123 }; 124 return 0; 125} 126#endif 127 128/* Check if VERSION of the info block PTR matches libgcov one. 129 Return 1 on success, or zero in case of versions mismatch. 130 If FILENAME is not NULL, its value used for reporting purposes 131 instead of value from the info block. */ 132 133static int 134gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, 135 const char *filename) 136{ 137 if (version != GCOV_VERSION) 138 { 139 char v[4], e[4]; 140 141 GCOV_UNSIGNED2STRING (v, version); 142 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 143 144 fprintf (stderr, 145 "profiling:%s:Version mismatch - expected %.4s got %.4s\n", 146 filename? filename : ptr->filename, e, v); 147 return 0; 148 } 149 return 1; 150} 151 152/* Dump the coverage counts. We merge with existing counts when 153 possible, to avoid growing the .da files ad infinitum. We use this 154 program's checksum to make sure we only accumulate whole program 155 statistics to the correct summary. An object file might be embedded 156 in two separate programs, and we must keep the two program 157 summaries separate. */ 158 159static void 160gcov_exit (void) 161{ 162 struct gcov_info *gi_ptr; 163 struct gcov_summary this_program; 164 struct gcov_summary all; 165 struct gcov_ctr_summary *cs_ptr; 166 const struct gcov_ctr_info *ci_ptr; 167 unsigned t_ix; 168 gcov_unsigned_t c_num; 169 const char *gcov_prefix; 170 int gcov_prefix_strip = 0; 171 size_t prefix_length; 172 char *gi_filename, *gi_filename_up; 173 174 memset (&all, 0, sizeof (all)); 175 /* Find the totals for this execution. */ 176 memset (&this_program, 0, sizeof (this_program)); 177 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 178 { 179 ci_ptr = gi_ptr->counts; 180 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 181 { 182 if (!((1 << t_ix) & gi_ptr->ctr_mask)) 183 continue; 184 185 cs_ptr = &this_program.ctrs[t_ix]; 186 cs_ptr->num += ci_ptr->num; 187 for (c_num = 0; c_num < ci_ptr->num; c_num++) 188 { 189 cs_ptr->sum_all += ci_ptr->values[c_num]; 190 if (cs_ptr->run_max < ci_ptr->values[c_num]) 191 cs_ptr->run_max = ci_ptr->values[c_num]; 192 } 193 ci_ptr++; 194 } 195 } 196 197 /* Get file name relocation prefix. Non-absolute values are ignored. */ 198 gcov_prefix = getenv("GCOV_PREFIX"); 199 if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix)) 200 { 201 /* Check if the level of dirs to strip off specified. */ 202 char *tmp = getenv("GCOV_PREFIX_STRIP"); 203 if (tmp) 204 { 205 gcov_prefix_strip = atoi (tmp); 206 /* Do not consider negative values. */ 207 if (gcov_prefix_strip < 0) 208 gcov_prefix_strip = 0; 209 } 210 211 prefix_length = strlen(gcov_prefix); 212 213 /* Remove an unnecessary trailing '/' */ 214 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) 215 prefix_length--; 216 } 217 else 218 prefix_length = 0; 219 220 /* Allocate and initialize the filename scratch space. */ 221 gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1); 222 if (prefix_length) 223 memcpy (gi_filename, gcov_prefix, prefix_length); 224 gi_filename_up = gi_filename + prefix_length; 225 226 /* Now merge each file. */ 227 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 228 { 229 struct gcov_summary this_object; 230 struct gcov_summary object, program; 231 gcov_type *values[GCOV_COUNTERS]; 232 const struct gcov_fn_info *fi_ptr; 233 unsigned fi_stride; 234 unsigned c_ix, f_ix, n_counts; 235 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; 236 int error = 0; 237 gcov_unsigned_t tag, length; 238 gcov_position_t summary_pos = 0; 239 gcov_position_t eof_pos = 0; 240 241 memset (&this_object, 0, sizeof (this_object)); 242 memset (&object, 0, sizeof (object)); 243 244 /* Build relocated filename, stripping off leading 245 directories from the initial filename if requested. */ 246 if (gcov_prefix_strip > 0) 247 { 248 int level = 0; 249 const char *fname = gi_ptr->filename; 250 const char *s; 251 252 /* Skip selected directory levels. */ 253 for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++) 254 if (IS_DIR_SEPARATOR(*s)) 255 { 256 fname = s; 257 level++; 258 }; 259 260 /* Update complete filename with stripped original. */ 261 strcpy (gi_filename_up, fname); 262 } 263 else 264 strcpy (gi_filename_up, gi_ptr->filename); 265 266 /* Totals for this object file. */ 267 ci_ptr = gi_ptr->counts; 268 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 269 { 270 if (!((1 << t_ix) & gi_ptr->ctr_mask)) 271 continue; 272 273 cs_ptr = &this_object.ctrs[t_ix]; 274 cs_ptr->num += ci_ptr->num; 275 for (c_num = 0; c_num < ci_ptr->num; c_num++) 276 { 277 cs_ptr->sum_all += ci_ptr->values[c_num]; 278 if (cs_ptr->run_max < ci_ptr->values[c_num]) 279 cs_ptr->run_max = ci_ptr->values[c_num]; 280 } 281 282 ci_ptr++; 283 } 284 285 c_ix = 0; 286 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 287 if ((1 << t_ix) & gi_ptr->ctr_mask) 288 { 289 values[c_ix] = gi_ptr->counts[c_ix].values; 290 c_ix++; 291 } 292 293 /* Calculate the function_info stride. This depends on the 294 number of counter types being measured. */ 295 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned); 296 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) 297 { 298 fi_stride += __alignof__ (struct gcov_fn_info) - 1; 299 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); 300 } 301 302 if (!gcov_open (gi_filename)) 303 { 304#ifdef TARGET_POSIX_IO 305 /* Open failed likely due to missed directory. 306 Create directory and retry to open file. */ 307 if (create_file_directory (gi_filename)) 308 { 309 fprintf (stderr, "profiling:%s:Skip\n", gi_filename); 310 continue; 311 } 312#endif 313 if (!gcov_open (gi_filename)) 314 { 315 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename); 316 continue; 317 } 318 } 319 320 tag = gcov_read_unsigned (); 321 if (tag) 322 { 323 /* Merge data from file. */ 324 if (tag != GCOV_DATA_MAGIC) 325 { 326 fprintf (stderr, "profiling:%s:Not a gcov data file\n", 327 gi_filename); 328 goto read_fatal; 329 } 330 length = gcov_read_unsigned (); 331 if (!gcov_version (gi_ptr, length, gi_filename)) 332 goto read_fatal; 333 334 length = gcov_read_unsigned (); 335 if (length != gi_ptr->stamp) 336 /* Read from a different compilation. Overwrite the file. */ 337 goto rewrite; 338 339 /* Merge execution counts for each function. */ 340 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 341 { 342 fi_ptr = (const struct gcov_fn_info *) 343 ((const char *) gi_ptr->functions + f_ix * fi_stride); 344 tag = gcov_read_unsigned (); 345 length = gcov_read_unsigned (); 346 347 /* Check function. */ 348 if (tag != GCOV_TAG_FUNCTION 349 || length != GCOV_TAG_FUNCTION_LENGTH 350 || gcov_read_unsigned () != fi_ptr->ident 351 || gcov_read_unsigned () != fi_ptr->checksum) 352 { 353 read_mismatch:; 354 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", 355 gi_filename, 356 f_ix + 1 ? "function" : "summaries"); 357 goto read_fatal; 358 } 359 360 c_ix = 0; 361 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 362 { 363 gcov_merge_fn merge; 364 365 if (!((1 << t_ix) & gi_ptr->ctr_mask)) 366 continue; 367 368 n_counts = fi_ptr->n_ctrs[c_ix]; 369 merge = gi_ptr->counts[c_ix].merge; 370 371 tag = gcov_read_unsigned (); 372 length = gcov_read_unsigned (); 373 if (tag != GCOV_TAG_FOR_COUNTER (t_ix) 374 || length != GCOV_TAG_COUNTER_LENGTH (n_counts)) 375 goto read_mismatch; 376 (*merge) (values[c_ix], n_counts); 377 values[c_ix] += n_counts; 378 c_ix++; 379 } 380 if ((error = gcov_is_error ())) 381 goto read_error; 382 } 383 384 f_ix = ~0u; 385 /* Check program & object summary */ 386 while (1) 387 { 388 int is_program; 389 390 eof_pos = gcov_position (); 391 tag = gcov_read_unsigned (); 392 if (!tag) 393 break; 394 395 length = gcov_read_unsigned (); 396 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; 397 if (length != GCOV_TAG_SUMMARY_LENGTH 398 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY)) 399 goto read_mismatch; 400 gcov_read_summary (is_program ? &program : &object); 401 if ((error = gcov_is_error ())) 402 goto read_error; 403 if (is_program && program.checksum == gcov_crc32) 404 { 405 summary_pos = eof_pos; 406 goto rewrite; 407 } 408 } 409 } 410 goto rewrite; 411 412 read_error:; 413 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" 414 : "profiling:%s:Error merging\n", gi_filename); 415 416 read_fatal:; 417 gcov_close (); 418 continue; 419 420 rewrite:; 421 gcov_rewrite (); 422 if (!summary_pos) 423 memset (&program, 0, sizeof (program)); 424 425 /* Merge the summaries. */ 426 f_ix = ~0u; 427 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 428 { 429 cs_obj = &object.ctrs[t_ix]; 430 cs_tobj = &this_object.ctrs[t_ix]; 431 cs_prg = &program.ctrs[t_ix]; 432 cs_tprg = &this_program.ctrs[t_ix]; 433 cs_all = &all.ctrs[t_ix]; 434 435 if ((1 << t_ix) & gi_ptr->ctr_mask) 436 { 437 if (!cs_obj->runs++) 438 cs_obj->num = cs_tobj->num; 439 else if (cs_obj->num != cs_tobj->num) 440 goto read_mismatch; 441 cs_obj->sum_all += cs_tobj->sum_all; 442 if (cs_obj->run_max < cs_tobj->run_max) 443 cs_obj->run_max = cs_tobj->run_max; 444 cs_obj->sum_max += cs_tobj->run_max; 445 446 if (!cs_prg->runs++) 447 cs_prg->num = cs_tprg->num; 448 else if (cs_prg->num != cs_tprg->num) 449 goto read_mismatch; 450 cs_prg->sum_all += cs_tprg->sum_all; 451 if (cs_prg->run_max < cs_tprg->run_max) 452 cs_prg->run_max = cs_tprg->run_max; 453 cs_prg->sum_max += cs_tprg->run_max; 454 } 455 else if (cs_obj->num || cs_prg->num) 456 goto read_mismatch; 457 458 if (!cs_all->runs && cs_prg->runs) 459 memcpy (cs_all, cs_prg, sizeof (*cs_all)); 460 else if (!all.checksum 461 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs) 462 && memcmp (cs_all, cs_prg, sizeof (*cs_all))) 463 { 464 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", 465 gi_filename, GCOV_LOCKED 466 ? "" : " or concurrent update without locking support"); 467 all.checksum = ~0u; 468 } 469 } 470 471 c_ix = 0; 472 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 473 if ((1 << t_ix) & gi_ptr->ctr_mask) 474 { 475 values[c_ix] = gi_ptr->counts[c_ix].values; 476 c_ix++; 477 } 478 479 program.checksum = gcov_crc32; 480 481 /* Write out the data. */ 482 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); 483 gcov_write_unsigned (gi_ptr->stamp); 484 485 /* Write execution counts for each function. */ 486 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 487 { 488 fi_ptr = (const struct gcov_fn_info *) 489 ((const char *) gi_ptr->functions + f_ix * fi_stride); 490 491 /* Announce function. */ 492 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH); 493 gcov_write_unsigned (fi_ptr->ident); 494 gcov_write_unsigned (fi_ptr->checksum); 495 496 c_ix = 0; 497 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 498 { 499 gcov_type *c_ptr; 500 501 if (!((1 << t_ix) & gi_ptr->ctr_mask)) 502 continue; 503 504 n_counts = fi_ptr->n_ctrs[c_ix]; 505 506 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), 507 GCOV_TAG_COUNTER_LENGTH (n_counts)); 508 c_ptr = values[c_ix]; 509 while (n_counts--) 510 gcov_write_counter (*c_ptr++); 511 512 values[c_ix] = c_ptr; 513 c_ix++; 514 } 515 } 516 517 /* Object file summary. */ 518 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); 519 520 /* Generate whole program statistics. */ 521 if (eof_pos) 522 gcov_seek (eof_pos); 523 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program); 524 if (!summary_pos) 525 gcov_write_unsigned (0); 526 if ((error = gcov_close ())) 527 fprintf (stderr, error < 0 ? 528 "profiling:%s:Overflow writing\n" : 529 "profiling:%s:Error writing\n", 530 gi_filename); 531 } 532} 533 534/* Add a new object file onto the bb chain. Invoked automatically 535 when running an object file's global ctors. */ 536 537void 538__gcov_init (struct gcov_info *info) 539{ 540 if (!info->version) 541 return; 542 if (gcov_version (info, info->version, 0)) 543 { 544 const char *ptr = info->filename; 545 gcov_unsigned_t crc32 = gcov_crc32; 546 size_t filename_length = strlen(info->filename); 547 548 /* Refresh the longest file name information */ 549 if (filename_length > gcov_max_filename) 550 gcov_max_filename = filename_length; 551 552 do 553 { 554 unsigned ix; 555 gcov_unsigned_t value = *ptr << 24; 556 557 for (ix = 8; ix--; value <<= 1) 558 { 559 gcov_unsigned_t feedback; 560 561 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; 562 crc32 <<= 1; 563 crc32 ^= feedback; 564 } 565 } 566 while (*ptr++); 567 568 gcov_crc32 = crc32; 569 570 if (!gcov_list) 571 atexit (gcov_exit); 572 573 info->next = gcov_list; 574 gcov_list = info; 575 } 576 info->version = 0; 577} 578 579/* Called before fork or exec - write out profile information gathered so 580 far and reset it to zero. This avoids duplication or loss of the 581 profile information gathered so far. */ 582 583void 584__gcov_flush (void) 585{ 586 const struct gcov_info *gi_ptr; 587 588 gcov_exit (); 589 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 590 { 591 unsigned t_ix; 592 const struct gcov_ctr_info *ci_ptr; 593 594 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++) 595 if ((1 << t_ix) & gi_ptr->ctr_mask) 596 { 597 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); 598 ci_ptr++; 599 } 600 } 601} 602 603#endif /* L_gcov */ 604 605#ifdef L_gcov_merge_add 606/* The profile merging function that just adds the counters. It is given 607 an array COUNTERS of N_COUNTERS old counters and it reads the same number 608 of counters from the gcov file. */ 609void 610__gcov_merge_add (gcov_type *counters, unsigned n_counters) 611{ 612 for (; n_counters; counters++, n_counters--) 613 *counters += gcov_read_counter (); 614} 615#endif /* L_gcov_merge_add */ 616 617#ifdef L_gcov_merge_single 618/* The profile merging function for choosing the most common value. 619 It is given an array COUNTERS of N_COUNTERS old counters and it 620 reads the same number of counters from the gcov file. The counters 621 are split into 3-tuples where the members of the tuple have 622 meanings: 623 624 -- the stored candidate on the most common value of the measured entity 625 -- counter 626 -- total number of evaluations of the value */ 627void 628__gcov_merge_single (gcov_type *counters, unsigned n_counters) 629{ 630 unsigned i, n_measures; 631 gcov_type value, counter, all; 632 633 gcc_assert (!(n_counters % 3)); 634 n_measures = n_counters / 3; 635 for (i = 0; i < n_measures; i++, counters += 3) 636 { 637 value = gcov_read_counter (); 638 counter = gcov_read_counter (); 639 all = gcov_read_counter (); 640 641 if (counters[0] == value) 642 counters[1] += counter; 643 else if (counter > counters[1]) 644 { 645 counters[0] = value; 646 counters[1] = counter - counters[1]; 647 } 648 else 649 counters[1] -= counter; 650 counters[2] += all; 651 } 652} 653#endif /* L_gcov_merge_single */ 654 655#ifdef L_gcov_merge_delta 656/* The profile merging function for choosing the most common 657 difference between two consecutive evaluations of the value. It is 658 given an array COUNTERS of N_COUNTERS old counters and it reads the 659 same number of counters from the gcov file. The counters are split 660 into 4-tuples where the members of the tuple have meanings: 661 662 -- the last value of the measured entity 663 -- the stored candidate on the most common difference 664 -- counter 665 -- total number of evaluations of the value */ 666void 667__gcov_merge_delta (gcov_type *counters, unsigned n_counters) 668{ 669 unsigned i, n_measures; 670 gcov_type last, value, counter, all; 671 672 gcc_assert (!(n_counters % 4)); 673 n_measures = n_counters / 4; 674 for (i = 0; i < n_measures; i++, counters += 4) 675 { 676 last = gcov_read_counter (); 677 value = gcov_read_counter (); 678 counter = gcov_read_counter (); 679 all = gcov_read_counter (); 680 681 if (counters[1] == value) 682 counters[2] += counter; 683 else if (counter > counters[2]) 684 { 685 counters[1] = value; 686 counters[2] = counter - counters[2]; 687 } 688 else 689 counters[2] -= counter; 690 counters[3] += all; 691 } 692} 693#endif /* L_gcov_merge_delta */ 694 695#ifdef L_gcov_interval_profiler 696/* If VALUE is in interval <START, START + STEPS - 1>, then increases the 697 corresponding counter in COUNTERS. If the VALUE is above or below 698 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased 699 instead. */ 700 701void 702__gcov_interval_profiler (gcov_type *counters, gcov_type value, 703 int start, unsigned steps) 704{ 705 gcov_type delta = value - start; 706 if (delta < 0) 707 counters[steps + 1]++; 708 else if (delta >= steps) 709 counters[steps]++; 710 else 711 counters[delta]++; 712} 713#endif 714 715#ifdef L_gcov_pow2_profiler 716/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise 717 COUNTERS[0] is incremented. */ 718 719void 720__gcov_pow2_profiler (gcov_type *counters, gcov_type value) 721{ 722 if (value & (value - 1)) 723 counters[0]++; 724 else 725 counters[1]++; 726} 727#endif 728 729#ifdef L_gcov_one_value_profiler 730/* Tries to determine the most common value among its inputs. Checks if the 731 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] 732 is incremented. If this is not the case and COUNTERS[1] is not zero, 733 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and 734 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this 735 function is called more than 50% of the time with one value, this value 736 will be in COUNTERS[0] in the end. 737 738 In any case, COUNTERS[2] is incremented. */ 739 740void 741__gcov_one_value_profiler (gcov_type *counters, gcov_type value) 742{ 743 if (value == counters[0]) 744 counters[1]++; 745 else if (counters[1] == 0) 746 { 747 counters[1] = 1; 748 counters[0] = value; 749 } 750 else 751 counters[1]--; 752 counters[2]++; 753} 754#endif 755 756#ifdef L_gcov_fork 757/* A wrapper for the fork function. Flushes the accumulated profiling data, so 758 that they are not counted twice. */ 759 760pid_t 761__gcov_fork (void) 762{ 763 __gcov_flush (); 764 return fork (); 765} 766#endif 767 768#ifdef L_gcov_execl 769/* A wrapper for the execl function. Flushes the accumulated profiling data, so 770 that they are not lost. */ 771 772int 773__gcov_execl (const char *path, const char *arg, ...) 774{ 775 va_list ap, aq; 776 unsigned i, length; 777 char **args; 778 779 __gcov_flush (); 780 781 va_start (ap, arg); 782 va_copy (aq, ap); 783 784 length = 2; 785 while (va_arg (ap, char *)) 786 length++; 787 va_end (ap); 788 789 args = (char **) alloca (length * sizeof (void *)); 790 args[0] = (char *) arg; 791 for (i = 1; i < length; i++) 792 args[i] = va_arg (aq, char *); 793 va_end (aq); 794 795 return execv (path, args); 796} 797#endif 798 799#ifdef L_gcov_execlp 800/* A wrapper for the execlp function. Flushes the accumulated profiling data, so 801 that they are not lost. */ 802 803int 804__gcov_execlp (const char *path, const char *arg, ...) 805{ 806 va_list ap, aq; 807 unsigned i, length; 808 char **args; 809 810 __gcov_flush (); 811 812 va_start (ap, arg); 813 va_copy (aq, ap); 814 815 length = 2; 816 while (va_arg (ap, char *)) 817 length++; 818 va_end (ap); 819 820 args = (char **) alloca (length * sizeof (void *)); 821 args[0] = (char *) arg; 822 for (i = 1; i < length; i++) 823 args[i] = va_arg (aq, char *); 824 va_end (aq); 825 826 return execvp (path, args); 827} 828#endif 829 830#ifdef L_gcov_execle 831/* A wrapper for the execle function. Flushes the accumulated profiling data, so 832 that they are not lost. */ 833 834int 835__gcov_execle (const char *path, const char *arg, ...) 836{ 837 va_list ap, aq; 838 unsigned i, length; 839 char **args; 840 char **envp; 841 842 __gcov_flush (); 843 844 va_start (ap, arg); 845 va_copy (aq, ap); 846 847 length = 2; 848 while (va_arg (ap, char *)) 849 length++; 850 va_end (ap); 851 852 args = (char **) alloca (length * sizeof (void *)); 853 args[0] = (char *) arg; 854 for (i = 1; i < length; i++) 855 args[i] = va_arg (aq, char *); 856 envp = va_arg (aq, char **); 857 va_end (aq); 858 859 return execve (path, args, envp); 860} 861#endif 862 863#ifdef L_gcov_execv 864/* A wrapper for the execv function. Flushes the accumulated profiling data, so 865 that they are not lost. */ 866 867int 868__gcov_execv (const char *path, char *const argv[]) 869{ 870 __gcov_flush (); 871 return execv (path, argv); 872} 873#endif 874 875#ifdef L_gcov_execvp 876/* A wrapper for the execvp function. Flushes the accumulated profiling data, so 877 that they are not lost. */ 878 879int 880__gcov_execvp (const char *path, char *const argv[]) 881{ 882 __gcov_flush (); 883 return execvp (path, argv); 884} 885#endif 886 887#ifdef L_gcov_execve 888/* A wrapper for the execve function. Flushes the accumulated profiling data, so 889 that they are not lost. */ 890 891int 892__gcov_execve (const char *path, char *const argv[], char *const envp[]) 893{ 894 __gcov_flush (); 895 return execve (path, argv, envp); 896} 897#endif 898#endif /* inhibit_libc */ 899