1 /* Gcov.c: prepend line execution counts and branch probabilities to a 2 source file. 3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 5 Free Software Foundation, Inc. 6 Contributed by James E. Wilson of Cygnus Support. 7 Mangled by Bob Manson of Cygnus Support. 8 Mangled further by Nathan Sidwell <nathan@codesourcery.com> 9 10 Gcov is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3, or (at your option) 13 any later version. 14 15 Gcov is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with Gcov; see the file COPYING3. If not see 22 <http://www.gnu.org/licenses/>. */ 23 24 /* ??? Print a list of the ten blocks with the highest execution counts, 25 and list the line numbers corresponding to those blocks. Also, perhaps 26 list the line numbers with the highest execution counts, only printing 27 the first if there are several which are all listed in the same block. */ 28 29 /* ??? Should have an option to print the number of basic blocks, and the 30 percent of them that are covered. */ 31 32 /* Need an option to show individual block counts, and show 33 probabilities of fall through arcs. */ 34 35 #include "config.h" 36 #include "system.h" 37 #include "coretypes.h" 38 #include "tm.h" 39 #include "intl.h" 40 #include "diagnostic.h" 41 #include "version.h" 42 43 #include <getopt.h> 44 45 #define IN_GCOV 1 46 #include "gcov-io.h" 47 #include "gcov-io.c" 48 49 /* The gcno file is generated by -ftest-coverage option. The gcda file is 50 generated by a program compiled with -fprofile-arcs. Their formats 51 are documented in gcov-io.h. */ 52 53 /* The functions in this file for creating and solution program flow graphs 54 are very similar to functions in the gcc source file profile.c. In 55 some places we make use of the knowledge of how profile.c works to 56 select particular algorithms here. */ 57 58 /* The code validates that the profile information read in corresponds 59 to the code currently being compiled. Rather than checking for 60 identical files, the code below computes a checksum on the CFG 61 (based on the order of basic blocks and the arcs in the CFG). If 62 the CFG checksum in the gcda file match the CFG checksum for the 63 code currently being compiled, the profile data will be used. */ 64 65 /* This is the size of the buffer used to read in source file lines. */ 66 67 struct function_info; 68 struct block_info; 69 struct source_info; 70 71 /* Describes an arc between two basic blocks. */ 72 73 typedef struct arc_info 74 { 75 /* source and destination blocks. */ 76 struct block_info *src; 77 struct block_info *dst; 78 79 /* transition counts. */ 80 gcov_type count; 81 /* used in cycle search, so that we do not clobber original counts. */ 82 gcov_type cs_count; 83 84 unsigned int count_valid : 1; 85 unsigned int on_tree : 1; 86 unsigned int fake : 1; 87 unsigned int fall_through : 1; 88 89 /* Arc to a catch handler. */ 90 unsigned int is_throw : 1; 91 92 /* Arc is for a function that abnormally returns. */ 93 unsigned int is_call_non_return : 1; 94 95 /* Arc is for catch/setjmp. */ 96 unsigned int is_nonlocal_return : 1; 97 98 /* Is an unconditional branch. */ 99 unsigned int is_unconditional : 1; 100 101 /* Loop making arc. */ 102 unsigned int cycle : 1; 103 104 /* Next branch on line. */ 105 struct arc_info *line_next; 106 107 /* Links to next arc on src and dst lists. */ 108 struct arc_info *succ_next; 109 struct arc_info *pred_next; 110 } arc_t; 111 112 /* Describes a basic block. Contains lists of arcs to successor and 113 predecessor blocks. */ 114 115 typedef struct block_info 116 { 117 /* Chain of exit and entry arcs. */ 118 arc_t *succ; 119 arc_t *pred; 120 121 /* Number of unprocessed exit and entry arcs. */ 122 gcov_type num_succ; 123 gcov_type num_pred; 124 125 /* Block execution count. */ 126 gcov_type count; 127 unsigned flags : 12; 128 unsigned count_valid : 1; 129 unsigned valid_chain : 1; 130 unsigned invalid_chain : 1; 131 unsigned exceptional : 1; 132 133 /* Block is a call instrumenting site. */ 134 unsigned is_call_site : 1; /* Does the call. */ 135 unsigned is_call_return : 1; /* Is the return. */ 136 137 /* Block is a landing pad for longjmp or throw. */ 138 unsigned is_nonlocal_return : 1; 139 140 union 141 { 142 struct 143 { 144 /* Array of line numbers and source files. source files are 145 introduced by a linenumber of zero, the next 'line number' is 146 the number of the source file. Always starts with a source 147 file. */ 148 unsigned *encoding; 149 unsigned num; 150 } line; /* Valid until blocks are linked onto lines */ 151 struct 152 { 153 /* Single line graph cycle workspace. Used for all-blocks 154 mode. */ 155 arc_t *arc; 156 unsigned ident; 157 } cycle; /* Used in all-blocks mode, after blocks are linked onto 158 lines. */ 159 } u; 160 161 /* Temporary chain for solving graph, and for chaining blocks on one 162 line. */ 163 struct block_info *chain; 164 165 } block_t; 166 167 /* Describes a single function. Contains an array of basic blocks. */ 168 169 typedef struct function_info 170 { 171 /* Name of function. */ 172 char *name; 173 unsigned ident; 174 unsigned lineno_checksum; 175 unsigned cfg_checksum; 176 177 /* The graph contains at least one fake incoming edge. */ 178 unsigned has_catch : 1; 179 180 /* Array of basic blocks. */ 181 block_t *blocks; 182 unsigned num_blocks; 183 unsigned blocks_executed; 184 185 /* Raw arc coverage counts. */ 186 gcov_type *counts; 187 unsigned num_counts; 188 189 /* First line number & file. */ 190 unsigned line; 191 unsigned src; 192 193 /* Next function in same source file. */ 194 struct function_info *line_next; 195 196 /* Next function. */ 197 struct function_info *next; 198 } function_t; 199 200 /* Describes coverage of a file or function. */ 201 202 typedef struct coverage_info 203 { 204 int lines; 205 int lines_executed; 206 207 int branches; 208 int branches_executed; 209 int branches_taken; 210 211 int calls; 212 int calls_executed; 213 214 char *name; 215 } coverage_t; 216 217 /* Describes a single line of source. Contains a chain of basic blocks 218 with code on it. */ 219 220 typedef struct line_info 221 { 222 gcov_type count; /* execution count */ 223 union 224 { 225 arc_t *branches; /* branches from blocks that end on this 226 line. Used for branch-counts when not 227 all-blocks mode. */ 228 block_t *blocks; /* blocks which start on this line. Used 229 in all-blocks mode. */ 230 } u; 231 unsigned exists : 1; 232 unsigned unexceptional : 1; 233 } line_t; 234 235 /* Describes a file mentioned in the block graph. Contains an array 236 of line info. */ 237 238 typedef struct source_info 239 { 240 /* Canonical name of source file. */ 241 char *name; 242 time_t file_time; 243 244 /* Array of line information. */ 245 line_t *lines; 246 unsigned num_lines; 247 248 coverage_t coverage; 249 250 /* Functions in this source file. These are in ascending line 251 number order. */ 252 function_t *functions; 253 } source_t; 254 255 typedef struct name_map 256 { 257 char *name; /* Source file name */ 258 unsigned src; /* Source file */ 259 } name_map_t; 260 261 /* Holds a list of function basic block graphs. */ 262 263 static function_t *functions; 264 static function_t **fn_end = &functions; 265 266 static source_t *sources; /* Array of source files */ 267 static unsigned n_sources; /* Number of sources */ 268 static unsigned a_sources; /* Allocated sources */ 269 270 static name_map_t *names; /* Mapping of file names to sources */ 271 static unsigned n_names; /* Number of names */ 272 static unsigned a_names; /* Allocated names */ 273 274 /* This holds data summary information. */ 275 276 static unsigned object_runs; 277 static unsigned program_count; 278 279 static unsigned total_lines; 280 static unsigned total_executed; 281 282 /* Modification time of graph file. */ 283 284 static time_t bbg_file_time; 285 286 /* Name and file pointer of the input file for the basic block graph. */ 287 288 static char *bbg_file_name; 289 290 /* Stamp of the bbg file */ 291 static unsigned bbg_stamp; 292 293 /* Name and file pointer of the input file for the arc count data. */ 294 295 static char *da_file_name; 296 297 /* Data file is missing. */ 298 299 static int no_data_file; 300 301 /* If there is several input files, compute and display results after 302 reading all data files. This way if two or more gcda file refer to 303 the same source file (eg inline subprograms in a .h file), the 304 counts are added. */ 305 306 static int multiple_files = 0; 307 308 /* Output branch probabilities. */ 309 310 static int flag_branches = 0; 311 312 /* Show unconditional branches too. */ 313 static int flag_unconditional = 0; 314 315 /* Output a gcov file if this is true. This is on by default, and can 316 be turned off by the -n option. */ 317 318 static int flag_gcov_file = 1; 319 320 /* Output progress indication if this is true. This is off by default 321 and can be turned on by the -d option. */ 322 323 static int flag_display_progress = 0; 324 325 /* For included files, make the gcov output file name include the name 326 of the input source file. For example, if x.h is included in a.c, 327 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ 328 329 static int flag_long_names = 0; 330 331 /* Output count information for every basic block, not merely those 332 that contain line number information. */ 333 334 static int flag_all_blocks = 0; 335 336 /* Output summary info for each function. */ 337 338 static int flag_function_summary = 0; 339 340 /* Object directory file prefix. This is the directory/file where the 341 graph and data files are looked for, if nonzero. */ 342 343 static char *object_directory = 0; 344 345 /* Source directory prefix. This is removed from source pathnames 346 that match, when generating the output file name. */ 347 348 static char *source_prefix = 0; 349 static size_t source_length = 0; 350 351 /* Only show data for sources with relative pathnames. Absolute ones 352 usually indicate a system header file, which although it may 353 contain inline functions, is usually uninteresting. */ 354 static int flag_relative_only = 0; 355 356 /* Preserve all pathname components. Needed when object files and 357 source files are in subdirectories. '/' is mangled as '#', '.' is 358 elided and '..' mangled to '^'. */ 359 360 static int flag_preserve_paths = 0; 361 362 /* Output the number of times a branch was taken as opposed to the percentage 363 of times it was taken. */ 364 365 static int flag_counts = 0; 366 367 /* Forward declarations. */ 368 static int process_args (int, char **); 369 static void print_usage (int) ATTRIBUTE_NORETURN; 370 static void print_version (void) ATTRIBUTE_NORETURN; 371 static void process_file (const char *); 372 static void generate_results (const char *); 373 static void create_file_names (const char *); 374 static int name_search (const void *, const void *); 375 static int name_sort (const void *, const void *); 376 static char *canonicalize_name (const char *); 377 static unsigned find_source (const char *); 378 static function_t *read_graph_file (void); 379 static int read_count_file (function_t *); 380 static void solve_flow_graph (function_t *); 381 static void find_exception_blocks (function_t *); 382 static void add_branch_counts (coverage_t *, const arc_t *); 383 static void add_line_counts (coverage_t *, function_t *); 384 static void executed_summary (unsigned, unsigned); 385 static void function_summary (const coverage_t *, const char *); 386 static const char *format_gcov (gcov_type, gcov_type, int); 387 static void accumulate_line_counts (source_t *); 388 static int output_branch_count (FILE *, int, const arc_t *); 389 static void output_lines (FILE *, const source_t *); 390 static char *make_gcov_file_name (const char *, const char *); 391 static char *mangle_name (const char *, char *); 392 static void release_structures (void); 393 static void release_function (function_t *); 394 extern int main (int, char **); 395 396 int 397 main (int argc, char **argv) 398 { 399 int argno; 400 int first_arg; 401 const char *p; 402 403 p = argv[0] + strlen (argv[0]); 404 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) 405 --p; 406 progname = p; 407 408 xmalloc_set_program_name (progname); 409 410 /* Unlock the stdio streams. */ 411 unlock_std_streams (); 412 413 gcc_init_libintl (); 414 415 diagnostic_initialize (global_dc, 0); 416 417 /* Handle response files. */ 418 expandargv (&argc, &argv); 419 420 a_names = 10; 421 names = XNEWVEC (name_map_t, a_names); 422 a_sources = 10; 423 sources = XNEWVEC (source_t, a_sources); 424 425 argno = process_args (argc, argv); 426 if (optind == argc) 427 print_usage (true); 428 429 if (argc - argno > 1) 430 multiple_files = 1; 431 432 first_arg = argno; 433 434 for (; argno != argc; argno++) 435 { 436 if (flag_display_progress) 437 printf("Processing file %d out of %d\n", 438 argno - first_arg + 1, argc - first_arg); 439 process_file (argv[argno]); 440 } 441 442 generate_results (multiple_files ? NULL : argv[argc - 1]); 443 444 release_structures (); 445 446 return 0; 447 } 448 449 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, 450 otherwise the output of --help. */ 451 452 static void 453 print_usage (int error_p) 454 { 455 FILE *file = error_p ? stderr : stdout; 456 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 457 458 fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n"); 459 fnotice (file, "Print code coverage information.\n\n"); 460 fnotice (file, " -h, --help Print this help, then exit\n"); 461 fnotice (file, " -v, --version Print version number, then exit\n"); 462 fnotice (file, " -a, --all-blocks Show information for every basic block\n"); 463 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n"); 464 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\ 465 rather than percentages\n"); 466 fnotice (file, " -n, --no-output Do not create an output file\n"); 467 fnotice (file, " -l, --long-file-names Use long output file names for included\n\ 468 source files\n"); 469 fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 470 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); 471 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n"); 472 fnotice (file, " -r, --relative-only Only show data for relative sources\n"); 473 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); 474 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); 475 fnotice (file, " -d, --display-progress Display progress information\n"); 476 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", 477 bug_report_url); 478 exit (status); 479 } 480 481 /* Print version information and exit. */ 482 483 static void 484 print_version (void) 485 { 486 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string); 487 fprintf (stdout, "Copyright %s 2012 Free Software Foundation, Inc.\n", 488 _("(C)")); 489 fnotice (stdout, 490 _("This is free software; see the source for copying conditions.\n" 491 "There is NO warranty; not even for MERCHANTABILITY or \n" 492 "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 493 exit (SUCCESS_EXIT_CODE); 494 } 495 496 static const struct option options[] = 497 { 498 { "help", no_argument, NULL, 'h' }, 499 { "version", no_argument, NULL, 'v' }, 500 { "all-blocks", no_argument, NULL, 'a' }, 501 { "branch-probabilities", no_argument, NULL, 'b' }, 502 { "branch-counts", no_argument, NULL, 'c' }, 503 { "no-output", no_argument, NULL, 'n' }, 504 { "long-file-names", no_argument, NULL, 'l' }, 505 { "function-summaries", no_argument, NULL, 'f' }, 506 { "preserve-paths", no_argument, NULL, 'p' }, 507 { "relative-only", no_argument, NULL, 'r' }, 508 { "object-directory", required_argument, NULL, 'o' }, 509 { "object-file", required_argument, NULL, 'o' }, 510 { "source-prefix", required_argument, NULL, 's' }, 511 { "unconditional-branches", no_argument, NULL, 'u' }, 512 { "display-progress", no_argument, NULL, 'd' }, 513 { 0, 0, 0, 0 } 514 }; 515 516 /* Process args, return index to first non-arg. */ 517 518 static int 519 process_args (int argc, char **argv) 520 { 521 int opt; 522 523 while ((opt = getopt_long (argc, argv, "abcdfhlno:s:pruv", options, NULL)) != -1) 524 { 525 switch (opt) 526 { 527 case 'a': 528 flag_all_blocks = 1; 529 break; 530 case 'b': 531 flag_branches = 1; 532 break; 533 case 'c': 534 flag_counts = 1; 535 break; 536 case 'f': 537 flag_function_summary = 1; 538 break; 539 case 'h': 540 print_usage (false); 541 /* print_usage will exit. */ 542 case 'l': 543 flag_long_names = 1; 544 break; 545 case 'n': 546 flag_gcov_file = 0; 547 break; 548 case 'o': 549 object_directory = optarg; 550 break; 551 case 's': 552 source_prefix = optarg; 553 source_length = strlen (source_prefix); 554 break; 555 case 'r': 556 flag_relative_only = 1; 557 break; 558 case 'p': 559 flag_preserve_paths = 1; 560 break; 561 case 'u': 562 flag_unconditional = 1; 563 break; 564 case 'd': 565 flag_display_progress = 1; 566 break; 567 case 'v': 568 print_version (); 569 /* print_version will exit. */ 570 default: 571 print_usage (true); 572 /* print_usage will exit. */ 573 } 574 } 575 576 return optind; 577 } 578 579 /* Process a single input file. */ 580 581 static void 582 process_file (const char *file_name) 583 { 584 function_t *fns; 585 586 create_file_names (file_name); 587 fns = read_graph_file (); 588 if (!fns) 589 return; 590 591 read_count_file (fns); 592 while (fns) 593 { 594 function_t *fn = fns; 595 596 fns = fn->next; 597 fn->next = NULL; 598 if (fn->counts) 599 { 600 unsigned src = fn->src; 601 unsigned line = fn->line; 602 unsigned block_no; 603 function_t *probe, **prev; 604 605 /* Now insert it into the source file's list of 606 functions. Normally functions will be encountered in 607 ascending order, so a simple scan is quick. Note we're 608 building this list in reverse order. */ 609 for (prev = &sources[src].functions; 610 (probe = *prev); prev = &probe->line_next) 611 if (probe->line <= line) 612 break; 613 fn->line_next = probe; 614 *prev = fn; 615 616 /* Mark last line in files touched by function. */ 617 for (block_no = 0; block_no != fn->num_blocks; block_no++) 618 { 619 unsigned *enc = fn->blocks[block_no].u.line.encoding; 620 unsigned num = fn->blocks[block_no].u.line.num; 621 622 for (; num--; enc++) 623 if (!*enc) 624 { 625 if (enc[1] != src) 626 { 627 if (line >= sources[src].num_lines) 628 sources[src].num_lines = line + 1; 629 line = 0; 630 src = enc[1]; 631 } 632 enc++; 633 num--; 634 } 635 else if (*enc > line) 636 line = *enc; 637 } 638 if (line >= sources[src].num_lines) 639 sources[src].num_lines = line + 1; 640 641 solve_flow_graph (fn); 642 if (fn->has_catch) 643 find_exception_blocks (fn); 644 *fn_end = fn; 645 fn_end = &fn->next; 646 } 647 else 648 /* The function was not in the executable -- some other 649 instance must have been selected. */ 650 release_function (fn); 651 } 652 } 653 654 static void 655 generate_results (const char *file_name) 656 { 657 unsigned ix; 658 source_t *src; 659 function_t *fn; 660 661 for (ix = n_sources, src = sources; ix--; src++) 662 if (src->num_lines) 663 src->lines = XCNEWVEC (line_t, src->num_lines); 664 665 for (fn = functions; fn; fn = fn->next) 666 { 667 coverage_t coverage; 668 669 memset (&coverage, 0, sizeof (coverage)); 670 coverage.name = fn->name; 671 add_line_counts (flag_function_summary ? &coverage : NULL, fn); 672 if (flag_function_summary) 673 { 674 function_summary (&coverage, "Function"); 675 fnotice (stdout, "\n"); 676 } 677 } 678 679 if (file_name) 680 { 681 name_map_t *name_map = (name_map_t *)bsearch 682 (file_name, names, n_names, sizeof (*names), name_search); 683 if (name_map) 684 file_name = sources[name_map->src].coverage.name; 685 else 686 file_name = canonicalize_name (file_name); 687 } 688 689 for (ix = n_sources, src = sources; ix--; src++) 690 { 691 if (flag_relative_only) 692 { 693 /* Ignore this source, if it is an absolute path (after 694 source prefix removal). */ 695 char first = src->coverage.name[0]; 696 697 #if HAVE_DOS_BASED_FILE_SYSTEM 698 if (first && src->coverage.name[1] == ':') 699 first = src->coverage.name[2]; 700 #endif 701 if (IS_DIR_SEPARATOR (first)) 702 continue; 703 } 704 705 accumulate_line_counts (src); 706 function_summary (&src->coverage, "File"); 707 total_lines += src->coverage.lines; 708 total_executed += src->coverage.lines_executed; 709 if (flag_gcov_file) 710 { 711 char *gcov_file_name 712 = make_gcov_file_name (file_name, src->coverage.name); 713 714 if (src->coverage.lines) 715 { 716 FILE *gcov_file = fopen (gcov_file_name, "w"); 717 718 if (gcov_file) 719 { 720 fnotice (stdout, "Creating '%s'\n", gcov_file_name); 721 output_lines (gcov_file, src); 722 if (ferror (gcov_file)) 723 fnotice (stderr, "Error writing output file '%s'\n", 724 gcov_file_name); 725 fclose (gcov_file); 726 } 727 else 728 fnotice (stderr, "Could not open output file '%s'\n", 729 gcov_file_name); 730 } 731 else 732 { 733 unlink (gcov_file_name); 734 fnotice (stdout, "Removing '%s'\n", gcov_file_name); 735 } 736 free (gcov_file_name); 737 } 738 fnotice (stdout, "\n"); 739 } 740 741 if (!file_name) 742 executed_summary (total_lines, total_executed); 743 } 744 745 /* Release a function structure */ 746 747 static void 748 release_function (function_t *fn) 749 { 750 unsigned ix; 751 block_t *block; 752 753 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++) 754 { 755 arc_t *arc, *arc_n; 756 757 for (arc = block->succ; arc; arc = arc_n) 758 { 759 arc_n = arc->succ_next; 760 free (arc); 761 } 762 } 763 free (fn->blocks); 764 free (fn->counts); 765 } 766 767 /* Release all memory used. */ 768 769 static void 770 release_structures (void) 771 { 772 unsigned ix; 773 function_t *fn; 774 775 for (ix = n_sources; ix--;) 776 free (sources[ix].lines); 777 free (sources); 778 779 for (ix = n_names; ix--;) 780 free (names[ix].name); 781 free (names); 782 783 while ((fn = functions)) 784 { 785 functions = fn->next; 786 release_function (fn); 787 } 788 } 789 790 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY 791 is not specified, these are named from FILE_NAME sans extension. If 792 OBJECT_DIRECTORY is specified and is a directory, the files are in that 793 directory, but named from the basename of the FILE_NAME, sans extension. 794 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file* 795 and the data files are named from that. */ 796 797 static void 798 create_file_names (const char *file_name) 799 { 800 char *cptr; 801 char *name; 802 int length = strlen (file_name); 803 int base; 804 805 /* Free previous file names. */ 806 free (bbg_file_name); 807 free (da_file_name); 808 da_file_name = bbg_file_name = NULL; 809 bbg_file_time = 0; 810 bbg_stamp = 0; 811 812 if (object_directory && object_directory[0]) 813 { 814 struct stat status; 815 816 length += strlen (object_directory) + 2; 817 name = XNEWVEC (char, length); 818 name[0] = 0; 819 820 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); 821 strcat (name, object_directory); 822 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1]))) 823 strcat (name, "/"); 824 } 825 else 826 { 827 name = XNEWVEC (char, length + 1); 828 strcpy (name, file_name); 829 base = 0; 830 } 831 832 if (base) 833 { 834 /* Append source file name. */ 835 const char *cptr = lbasename (file_name); 836 strcat (name, cptr ? cptr : file_name); 837 } 838 839 /* Remove the extension. */ 840 cptr = strrchr (name, '.'); 841 if (cptr) 842 *cptr = 0; 843 844 length = strlen (name); 845 846 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1); 847 strcpy (bbg_file_name, name); 848 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); 849 850 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1); 851 strcpy (da_file_name, name); 852 strcpy (da_file_name + length, GCOV_DATA_SUFFIX); 853 854 free (name); 855 return; 856 } 857 858 /* A is a string and B is a pointer to name_map_t. Compare for file 859 name orderability. */ 860 861 static int 862 name_search (const void *a_, const void *b_) 863 { 864 const char *a = (const char *)a_; 865 const name_map_t *b = (const name_map_t *)b_; 866 867 #if HAVE_DOS_BASED_FILE_SYSTEM 868 return strcasecmp (a, b->name); 869 #else 870 return strcmp (a, b->name); 871 #endif 872 } 873 874 /* A and B are a pointer to name_map_t. Compare for file name 875 orderability. */ 876 877 static int 878 name_sort (const void *a_, const void *b_) 879 { 880 const name_map_t *a = (const name_map_t *)a_; 881 return name_search (a->name, b_); 882 } 883 884 /* Find or create a source file structure for FILE_NAME. Copies 885 FILE_NAME on creation */ 886 887 static unsigned 888 find_source (const char *file_name) 889 { 890 name_map_t *name_map; 891 char *canon; 892 unsigned idx; 893 struct stat status; 894 895 if (!file_name) 896 file_name = "<unknown>"; 897 name_map = (name_map_t *)bsearch 898 (file_name, names, n_names, sizeof (*names), name_search); 899 if (name_map) 900 { 901 idx = name_map->src; 902 goto check_date; 903 } 904 905 if (n_names + 2 > a_names) 906 { 907 /* Extend the name map array -- we'll be inserting one or two 908 entries. */ 909 a_names *= 2; 910 name_map = XNEWVEC (name_map_t, a_names); 911 memcpy (name_map, names, n_names * sizeof (*names)); 912 free (names); 913 names = name_map; 914 } 915 916 /* Not found, try the canonical name. */ 917 canon = canonicalize_name (file_name); 918 name_map = (name_map_t *)bsearch 919 (canon, names, n_names, sizeof (*names), name_search); 920 if (!name_map) 921 { 922 /* Not found with canonical name, create a new source. */ 923 source_t *src; 924 925 if (n_sources == a_sources) 926 { 927 a_sources *= 2; 928 src = XNEWVEC (source_t, a_sources); 929 memcpy (src, sources, n_sources * sizeof (*sources)); 930 free (sources); 931 sources = src; 932 } 933 934 idx = n_sources; 935 936 name_map = &names[n_names++]; 937 name_map->name = canon; 938 name_map->src = idx; 939 940 src = &sources[n_sources++]; 941 memset (src, 0, sizeof (*src)); 942 src->name = canon; 943 src->coverage.name = src->name; 944 if (source_length 945 #if HAVE_DOS_BASED_FILE_SYSTEM 946 /* You lose if separators don't match exactly in the 947 prefix. */ 948 && !strncasecmp (source_prefix, src->coverage.name, source_length) 949 #else 950 && !strncmp (source_prefix, src->coverage.name, source_length) 951 #endif 952 && IS_DIR_SEPARATOR (src->coverage.name[source_length])) 953 src->coverage.name += source_length + 1; 954 if (!stat (src->name, &status)) 955 src->file_time = status.st_mtime; 956 } 957 else 958 idx = name_map->src; 959 960 if (name_search (file_name, name_map)) 961 { 962 /* Append the non-canonical name. */ 963 name_map = &names[n_names++]; 964 name_map->name = xstrdup (file_name); 965 name_map->src = idx; 966 } 967 968 /* Resort the name map. */ 969 qsort (names, n_names, sizeof (*names), name_sort); 970 971 check_date: 972 if (sources[idx].file_time > bbg_file_time) 973 { 974 static int info_emitted; 975 976 fnotice (stderr, "%s:source file is newer than graph file '%s'\n", 977 file_name, bbg_file_name); 978 if (!info_emitted) 979 { 980 fnotice (stderr, 981 "(the message is only displayed one per source file)\n"); 982 info_emitted = 1; 983 } 984 sources[idx].file_time = 0; 985 } 986 987 return idx; 988 } 989 990 /* Read the graph file. Return list of functions read -- in reverse order. */ 991 992 static function_t * 993 read_graph_file (void) 994 { 995 unsigned version; 996 unsigned current_tag = 0; 997 function_t *fn = NULL; 998 function_t *fns = NULL; 999 function_t **fns_end = &fns; 1000 unsigned src_idx = 0; 1001 unsigned ix; 1002 unsigned tag; 1003 1004 if (!gcov_open (bbg_file_name, 1)) 1005 { 1006 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name); 1007 return fns; 1008 } 1009 bbg_file_time = gcov_time (); 1010 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) 1011 { 1012 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name); 1013 gcov_close (); 1014 return fns; 1015 } 1016 1017 version = gcov_read_unsigned (); 1018 if (version != GCOV_VERSION) 1019 { 1020 char v[4], e[4]; 1021 1022 GCOV_UNSIGNED2STRING (v, version); 1023 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 1024 1025 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n", 1026 bbg_file_name, v, e); 1027 } 1028 bbg_stamp = gcov_read_unsigned (); 1029 1030 while ((tag = gcov_read_unsigned ())) 1031 { 1032 unsigned length = gcov_read_unsigned (); 1033 gcov_position_t base = gcov_position (); 1034 1035 if (tag == GCOV_TAG_FUNCTION) 1036 { 1037 char *function_name; 1038 unsigned ident, lineno; 1039 unsigned lineno_checksum, cfg_checksum; 1040 1041 ident = gcov_read_unsigned (); 1042 lineno_checksum = gcov_read_unsigned (); 1043 cfg_checksum = gcov_read_unsigned (); 1044 function_name = xstrdup (gcov_read_string ()); 1045 src_idx = find_source (gcov_read_string ()); 1046 lineno = gcov_read_unsigned (); 1047 1048 fn = XCNEW (function_t); 1049 fn->name = function_name; 1050 fn->ident = ident; 1051 fn->lineno_checksum = lineno_checksum; 1052 fn->cfg_checksum = cfg_checksum; 1053 fn->src = src_idx; 1054 fn->line = lineno; 1055 1056 fn->line_next = NULL; 1057 fn->next = NULL; 1058 *fns_end = fn; 1059 fns_end = &fn->next; 1060 current_tag = tag; 1061 } 1062 else if (fn && tag == GCOV_TAG_BLOCKS) 1063 { 1064 if (fn->blocks) 1065 fnotice (stderr, "%s:already seen blocks for '%s'\n", 1066 bbg_file_name, fn->name); 1067 else 1068 { 1069 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length); 1070 fn->num_blocks = num_blocks; 1071 1072 fn->blocks = XCNEWVEC (block_t, fn->num_blocks); 1073 for (ix = 0; ix != num_blocks; ix++) 1074 fn->blocks[ix].flags = gcov_read_unsigned (); 1075 } 1076 } 1077 else if (fn && tag == GCOV_TAG_ARCS) 1078 { 1079 unsigned src = gcov_read_unsigned (); 1080 unsigned num_dests = GCOV_TAG_ARCS_NUM (length); 1081 block_t *src_blk = &fn->blocks[src]; 1082 unsigned mark_catches = 0; 1083 struct arc_info *arc; 1084 1085 if (src >= fn->num_blocks || fn->blocks[src].succ) 1086 goto corrupt; 1087 1088 while (num_dests--) 1089 { 1090 unsigned dest = gcov_read_unsigned (); 1091 unsigned flags = gcov_read_unsigned (); 1092 1093 if (dest >= fn->num_blocks) 1094 goto corrupt; 1095 arc = XCNEW (arc_t); 1096 1097 arc->dst = &fn->blocks[dest]; 1098 arc->src = src_blk; 1099 1100 arc->count = 0; 1101 arc->count_valid = 0; 1102 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); 1103 arc->fake = !!(flags & GCOV_ARC_FAKE); 1104 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); 1105 1106 arc->succ_next = src_blk->succ; 1107 src_blk->succ = arc; 1108 src_blk->num_succ++; 1109 1110 arc->pred_next = fn->blocks[dest].pred; 1111 fn->blocks[dest].pred = arc; 1112 fn->blocks[dest].num_pred++; 1113 1114 if (arc->fake) 1115 { 1116 if (src) 1117 { 1118 /* Exceptional exit from this function, the 1119 source block must be a call. */ 1120 fn->blocks[src].is_call_site = 1; 1121 arc->is_call_non_return = 1; 1122 mark_catches = 1; 1123 } 1124 else 1125 { 1126 /* Non-local return from a callee of this 1127 function. The destination block is a setjmp. */ 1128 arc->is_nonlocal_return = 1; 1129 fn->blocks[dest].is_nonlocal_return = 1; 1130 } 1131 } 1132 1133 if (!arc->on_tree) 1134 fn->num_counts++; 1135 } 1136 1137 if (mark_catches) 1138 { 1139 /* We have a fake exit from this block. The other 1140 non-fall through exits must be to catch handlers. 1141 Mark them as catch arcs. */ 1142 1143 for (arc = src_blk->succ; arc; arc = arc->succ_next) 1144 if (!arc->fake && !arc->fall_through) 1145 { 1146 arc->is_throw = 1; 1147 fn->has_catch = 1; 1148 } 1149 } 1150 } 1151 else if (fn && tag == GCOV_TAG_LINES) 1152 { 1153 unsigned blockno = gcov_read_unsigned (); 1154 unsigned *line_nos = XCNEWVEC (unsigned, length - 1); 1155 1156 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding) 1157 goto corrupt; 1158 1159 for (ix = 0; ; ) 1160 { 1161 unsigned lineno = gcov_read_unsigned (); 1162 1163 if (lineno) 1164 { 1165 if (!ix) 1166 { 1167 line_nos[ix++] = 0; 1168 line_nos[ix++] = src_idx; 1169 } 1170 line_nos[ix++] = lineno; 1171 } 1172 else 1173 { 1174 const char *file_name = gcov_read_string (); 1175 1176 if (!file_name) 1177 break; 1178 src_idx = find_source (file_name); 1179 line_nos[ix++] = 0; 1180 line_nos[ix++] = src_idx; 1181 } 1182 } 1183 1184 fn->blocks[blockno].u.line.encoding = line_nos; 1185 fn->blocks[blockno].u.line.num = ix; 1186 } 1187 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) 1188 { 1189 fn = NULL; 1190 current_tag = 0; 1191 } 1192 gcov_sync (base, length); 1193 if (gcov_is_error ()) 1194 { 1195 corrupt:; 1196 fnotice (stderr, "%s:corrupted\n", bbg_file_name); 1197 break; 1198 } 1199 } 1200 gcov_close (); 1201 1202 if (!fns) 1203 fnotice (stderr, "%s:no functions found\n", bbg_file_name); 1204 1205 return fns; 1206 } 1207 1208 /* Reads profiles from the count file and attach to each 1209 function. Return nonzero if fatal error. */ 1210 1211 static int 1212 read_count_file (function_t *fns) 1213 { 1214 unsigned ix; 1215 unsigned version; 1216 unsigned tag; 1217 function_t *fn = NULL; 1218 int error = 0; 1219 1220 if (!gcov_open (da_file_name, 1)) 1221 { 1222 fnotice (stderr, "%s:cannot open data file, assuming not executed\n", 1223 da_file_name); 1224 no_data_file = 1; 1225 return 0; 1226 } 1227 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) 1228 { 1229 fnotice (stderr, "%s:not a gcov data file\n", da_file_name); 1230 cleanup:; 1231 gcov_close (); 1232 return 1; 1233 } 1234 version = gcov_read_unsigned (); 1235 if (version != GCOV_VERSION) 1236 { 1237 char v[4], e[4]; 1238 1239 GCOV_UNSIGNED2STRING (v, version); 1240 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 1241 1242 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n", 1243 da_file_name, v, e); 1244 } 1245 tag = gcov_read_unsigned (); 1246 if (tag != bbg_stamp) 1247 { 1248 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name); 1249 goto cleanup; 1250 } 1251 1252 while ((tag = gcov_read_unsigned ())) 1253 { 1254 unsigned length = gcov_read_unsigned (); 1255 unsigned long base = gcov_position (); 1256 1257 if (tag == GCOV_TAG_PROGRAM_SUMMARY) 1258 { 1259 struct gcov_summary summary; 1260 gcov_read_summary (&summary); 1261 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs; 1262 program_count++; 1263 } 1264 else if (tag == GCOV_TAG_FUNCTION && !length) 1265 ; /* placeholder */ 1266 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH) 1267 { 1268 unsigned ident; 1269 struct function_info *fn_n; 1270 1271 /* Try to find the function in the list. To speed up the 1272 search, first start from the last function found. */ 1273 ident = gcov_read_unsigned (); 1274 fn_n = fns; 1275 for (fn = fn ? fn->next : NULL; ; fn = fn->next) 1276 { 1277 if (fn) 1278 ; 1279 else if ((fn = fn_n)) 1280 fn_n = NULL; 1281 else 1282 { 1283 fnotice (stderr, "%s:unknown function '%u'\n", 1284 da_file_name, ident); 1285 break; 1286 } 1287 if (fn->ident == ident) 1288 break; 1289 } 1290 1291 if (!fn) 1292 ; 1293 else if (gcov_read_unsigned () != fn->lineno_checksum 1294 || gcov_read_unsigned () != fn->cfg_checksum) 1295 { 1296 mismatch:; 1297 fnotice (stderr, "%s:profile mismatch for '%s'\n", 1298 da_file_name, fn->name); 1299 goto cleanup; 1300 } 1301 } 1302 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) 1303 { 1304 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) 1305 goto mismatch; 1306 1307 if (!fn->counts) 1308 fn->counts = XCNEWVEC (gcov_type, fn->num_counts); 1309 1310 for (ix = 0; ix != fn->num_counts; ix++) 1311 fn->counts[ix] += gcov_read_counter (); 1312 } 1313 gcov_sync (base, length); 1314 if ((error = gcov_is_error ())) 1315 { 1316 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", 1317 da_file_name); 1318 goto cleanup; 1319 } 1320 } 1321 1322 gcov_close (); 1323 return 0; 1324 } 1325 1326 /* Solve the flow graph. Propagate counts from the instrumented arcs 1327 to the blocks and the uninstrumented arcs. */ 1328 1329 static void 1330 solve_flow_graph (function_t *fn) 1331 { 1332 unsigned ix; 1333 arc_t *arc; 1334 gcov_type *count_ptr = fn->counts; 1335 block_t *blk; 1336 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ 1337 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ 1338 1339 /* The arcs were built in reverse order. Fix that now. */ 1340 for (ix = fn->num_blocks; ix--;) 1341 { 1342 arc_t *arc_p, *arc_n; 1343 1344 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; 1345 arc_p = arc, arc = arc_n) 1346 { 1347 arc_n = arc->succ_next; 1348 arc->succ_next = arc_p; 1349 } 1350 fn->blocks[ix].succ = arc_p; 1351 1352 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc; 1353 arc_p = arc, arc = arc_n) 1354 { 1355 arc_n = arc->pred_next; 1356 arc->pred_next = arc_p; 1357 } 1358 fn->blocks[ix].pred = arc_p; 1359 } 1360 1361 if (fn->num_blocks < 2) 1362 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n", 1363 bbg_file_name, fn->name); 1364 else 1365 { 1366 if (fn->blocks[0].num_pred) 1367 fnotice (stderr, "%s:'%s' has arcs to entry block\n", 1368 bbg_file_name, fn->name); 1369 else 1370 /* We can't deduce the entry block counts from the lack of 1371 predecessors. */ 1372 fn->blocks[0].num_pred = ~(unsigned)0; 1373 1374 if (fn->blocks[fn->num_blocks - 1].num_succ) 1375 fnotice (stderr, "%s:'%s' has arcs from exit block\n", 1376 bbg_file_name, fn->name); 1377 else 1378 /* Likewise, we can't deduce exit block counts from the lack 1379 of its successors. */ 1380 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0; 1381 } 1382 1383 /* Propagate the measured counts, this must be done in the same 1384 order as the code in profile.c */ 1385 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++) 1386 { 1387 block_t const *prev_dst = NULL; 1388 int out_of_order = 0; 1389 int non_fake_succ = 0; 1390 1391 for (arc = blk->succ; arc; arc = arc->succ_next) 1392 { 1393 if (!arc->fake) 1394 non_fake_succ++; 1395 1396 if (!arc->on_tree) 1397 { 1398 if (count_ptr) 1399 arc->count = *count_ptr++; 1400 arc->count_valid = 1; 1401 blk->num_succ--; 1402 arc->dst->num_pred--; 1403 } 1404 if (prev_dst && prev_dst > arc->dst) 1405 out_of_order = 1; 1406 prev_dst = arc->dst; 1407 } 1408 if (non_fake_succ == 1) 1409 { 1410 /* If there is only one non-fake exit, it is an 1411 unconditional branch. */ 1412 for (arc = blk->succ; arc; arc = arc->succ_next) 1413 if (!arc->fake) 1414 { 1415 arc->is_unconditional = 1; 1416 /* If this block is instrumenting a call, it might be 1417 an artificial block. It is not artificial if it has 1418 a non-fallthrough exit, or the destination of this 1419 arc has more than one entry. Mark the destination 1420 block as a return site, if none of those conditions 1421 hold. */ 1422 if (blk->is_call_site && arc->fall_through 1423 && arc->dst->pred == arc && !arc->pred_next) 1424 arc->dst->is_call_return = 1; 1425 } 1426 } 1427 1428 /* Sort the successor arcs into ascending dst order. profile.c 1429 normally produces arcs in the right order, but sometimes with 1430 one or two out of order. We're not using a particularly 1431 smart sort. */ 1432 if (out_of_order) 1433 { 1434 arc_t *start = blk->succ; 1435 unsigned changes = 1; 1436 1437 while (changes) 1438 { 1439 arc_t *arc, *arc_p, *arc_n; 1440 1441 changes = 0; 1442 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) 1443 { 1444 if (arc->dst > arc_n->dst) 1445 { 1446 changes = 1; 1447 if (arc_p) 1448 arc_p->succ_next = arc_n; 1449 else 1450 start = arc_n; 1451 arc->succ_next = arc_n->succ_next; 1452 arc_n->succ_next = arc; 1453 arc_p = arc_n; 1454 } 1455 else 1456 { 1457 arc_p = arc; 1458 arc = arc_n; 1459 } 1460 } 1461 } 1462 blk->succ = start; 1463 } 1464 1465 /* Place it on the invalid chain, it will be ignored if that's 1466 wrong. */ 1467 blk->invalid_chain = 1; 1468 blk->chain = invalid_blocks; 1469 invalid_blocks = blk; 1470 } 1471 1472 while (invalid_blocks || valid_blocks) 1473 { 1474 while ((blk = invalid_blocks)) 1475 { 1476 gcov_type total = 0; 1477 const arc_t *arc; 1478 1479 invalid_blocks = blk->chain; 1480 blk->invalid_chain = 0; 1481 if (!blk->num_succ) 1482 for (arc = blk->succ; arc; arc = arc->succ_next) 1483 total += arc->count; 1484 else if (!blk->num_pred) 1485 for (arc = blk->pred; arc; arc = arc->pred_next) 1486 total += arc->count; 1487 else 1488 continue; 1489 1490 blk->count = total; 1491 blk->count_valid = 1; 1492 blk->chain = valid_blocks; 1493 blk->valid_chain = 1; 1494 valid_blocks = blk; 1495 } 1496 while ((blk = valid_blocks)) 1497 { 1498 gcov_type total; 1499 arc_t *arc, *inv_arc; 1500 1501 valid_blocks = blk->chain; 1502 blk->valid_chain = 0; 1503 if (blk->num_succ == 1) 1504 { 1505 block_t *dst; 1506 1507 total = blk->count; 1508 inv_arc = NULL; 1509 for (arc = blk->succ; arc; arc = arc->succ_next) 1510 { 1511 total -= arc->count; 1512 if (!arc->count_valid) 1513 inv_arc = arc; 1514 } 1515 dst = inv_arc->dst; 1516 inv_arc->count_valid = 1; 1517 inv_arc->count = total; 1518 blk->num_succ--; 1519 dst->num_pred--; 1520 if (dst->count_valid) 1521 { 1522 if (dst->num_pred == 1 && !dst->valid_chain) 1523 { 1524 dst->chain = valid_blocks; 1525 dst->valid_chain = 1; 1526 valid_blocks = dst; 1527 } 1528 } 1529 else 1530 { 1531 if (!dst->num_pred && !dst->invalid_chain) 1532 { 1533 dst->chain = invalid_blocks; 1534 dst->invalid_chain = 1; 1535 invalid_blocks = dst; 1536 } 1537 } 1538 } 1539 if (blk->num_pred == 1) 1540 { 1541 block_t *src; 1542 1543 total = blk->count; 1544 inv_arc = NULL; 1545 for (arc = blk->pred; arc; arc = arc->pred_next) 1546 { 1547 total -= arc->count; 1548 if (!arc->count_valid) 1549 inv_arc = arc; 1550 } 1551 src = inv_arc->src; 1552 inv_arc->count_valid = 1; 1553 inv_arc->count = total; 1554 blk->num_pred--; 1555 src->num_succ--; 1556 if (src->count_valid) 1557 { 1558 if (src->num_succ == 1 && !src->valid_chain) 1559 { 1560 src->chain = valid_blocks; 1561 src->valid_chain = 1; 1562 valid_blocks = src; 1563 } 1564 } 1565 else 1566 { 1567 if (!src->num_succ && !src->invalid_chain) 1568 { 1569 src->chain = invalid_blocks; 1570 src->invalid_chain = 1; 1571 invalid_blocks = src; 1572 } 1573 } 1574 } 1575 } 1576 } 1577 1578 /* If the graph has been correctly solved, every block will have a 1579 valid count. */ 1580 for (ix = 0; ix < fn->num_blocks; ix++) 1581 if (!fn->blocks[ix].count_valid) 1582 { 1583 fnotice (stderr, "%s:graph is unsolvable for '%s'\n", 1584 bbg_file_name, fn->name); 1585 break; 1586 } 1587 } 1588 1589 /* Mark all the blocks only reachable via an incoming catch. */ 1590 1591 static void 1592 find_exception_blocks (function_t *fn) 1593 { 1594 unsigned ix; 1595 block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks); 1596 1597 /* First mark all blocks as exceptional. */ 1598 for (ix = fn->num_blocks; ix--;) 1599 fn->blocks[ix].exceptional = 1; 1600 1601 /* Now mark all the blocks reachable via non-fake edges */ 1602 queue[0] = fn->blocks; 1603 queue[0]->exceptional = 0; 1604 for (ix = 1; ix;) 1605 { 1606 block_t *block = queue[--ix]; 1607 const arc_t *arc; 1608 1609 for (arc = block->succ; arc; arc = arc->succ_next) 1610 if (!arc->fake && !arc->is_throw && arc->dst->exceptional) 1611 { 1612 arc->dst->exceptional = 0; 1613 queue[ix++] = arc->dst; 1614 } 1615 } 1616 } 1617 1618 1619 /* Increment totals in COVERAGE according to arc ARC. */ 1620 1621 static void 1622 add_branch_counts (coverage_t *coverage, const arc_t *arc) 1623 { 1624 if (arc->is_call_non_return) 1625 { 1626 coverage->calls++; 1627 if (arc->src->count) 1628 coverage->calls_executed++; 1629 } 1630 else if (!arc->is_unconditional) 1631 { 1632 coverage->branches++; 1633 if (arc->src->count) 1634 coverage->branches_executed++; 1635 if (arc->count) 1636 coverage->branches_taken++; 1637 } 1638 } 1639 1640 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute 1641 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. 1642 If DP is zero, no decimal point is printed. Only print 100% when 1643 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply 1644 format TOP. Return pointer to a static string. */ 1645 1646 static char const * 1647 format_gcov (gcov_type top, gcov_type bottom, int dp) 1648 { 1649 static char buffer[20]; 1650 1651 if (dp >= 0) 1652 { 1653 float ratio = bottom ? (float)top / bottom : 0; 1654 int ix; 1655 unsigned limit = 100; 1656 unsigned percent; 1657 1658 for (ix = dp; ix--; ) 1659 limit *= 10; 1660 1661 percent = (unsigned) (ratio * limit + (float)0.5); 1662 if (percent <= 0 && top) 1663 percent = 1; 1664 else if (percent >= limit && top != bottom) 1665 percent = limit - 1; 1666 ix = sprintf (buffer, "%.*u%%", dp + 1, percent); 1667 if (dp) 1668 { 1669 dp++; 1670 do 1671 { 1672 buffer[ix+1] = buffer[ix]; 1673 ix--; 1674 } 1675 while (dp--); 1676 buffer[ix + 1] = '.'; 1677 } 1678 } 1679 else 1680 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top); 1681 1682 return buffer; 1683 } 1684 1685 /* Summary of execution */ 1686 1687 static void 1688 executed_summary (unsigned lines, unsigned executed) 1689 { 1690 if (lines) 1691 fnotice (stdout, "Lines executed:%s of %d\n", 1692 format_gcov (executed, lines, 2), lines); 1693 else 1694 fnotice (stdout, "No executable lines\n"); 1695 } 1696 1697 /* Output summary info for a function or file. */ 1698 1699 static void 1700 function_summary (const coverage_t *coverage, const char *title) 1701 { 1702 fnotice (stdout, "%s '%s'\n", title, coverage->name); 1703 executed_summary (coverage->lines, coverage->lines_executed); 1704 1705 if (flag_branches) 1706 { 1707 if (coverage->branches) 1708 { 1709 fnotice (stdout, "Branches executed:%s of %d\n", 1710 format_gcov (coverage->branches_executed, 1711 coverage->branches, 2), 1712 coverage->branches); 1713 fnotice (stdout, "Taken at least once:%s of %d\n", 1714 format_gcov (coverage->branches_taken, 1715 coverage->branches, 2), 1716 coverage->branches); 1717 } 1718 else 1719 fnotice (stdout, "No branches\n"); 1720 if (coverage->calls) 1721 fnotice (stdout, "Calls executed:%s of %d\n", 1722 format_gcov (coverage->calls_executed, coverage->calls, 2), 1723 coverage->calls); 1724 else 1725 fnotice (stdout, "No calls\n"); 1726 } 1727 } 1728 1729 /* Canonicalize the filename NAME by canonicalizing directory 1730 separators, eliding . components and resolving .. components 1731 appropriately. Always returns a unique string. */ 1732 1733 static char * 1734 canonicalize_name (const char *name) 1735 { 1736 /* The canonical name cannot be longer than the incoming name. */ 1737 char *result = XNEWVEC (char, strlen (name) + 1); 1738 const char *base = name, *probe; 1739 char *ptr = result; 1740 char *dd_base; 1741 int slash = 0; 1742 1743 #if HAVE_DOS_BASED_FILE_SYSTEM 1744 if (base[0] && base[1] == ':') 1745 { 1746 result[0] = base[0]; 1747 result[1] = ':'; 1748 base += 2; 1749 ptr += 2; 1750 } 1751 #endif 1752 for (dd_base = ptr; *base; base = probe) 1753 { 1754 size_t len; 1755 1756 for (probe = base; *probe; probe++) 1757 if (IS_DIR_SEPARATOR (*probe)) 1758 break; 1759 1760 len = probe - base; 1761 if (len == 1 && base[0] == '.') 1762 /* Elide a '.' directory */ 1763 ; 1764 else if (len == 2 && base[0] == '.' && base[1] == '.') 1765 { 1766 /* '..', we can only elide it and the previous directory, if 1767 we're not a symlink. */ 1768 struct stat ATTRIBUTE_UNUSED buf; 1769 1770 *ptr = 0; 1771 if (dd_base == ptr 1772 #if defined (S_ISLNK) 1773 /* S_ISLNK is not POSIX.1-1996. */ 1774 || stat (result, &buf) || S_ISLNK (buf.st_mode) 1775 #endif 1776 ) 1777 { 1778 /* Cannot elide, or unreadable or a symlink. */ 1779 dd_base = ptr + 2 + slash; 1780 goto regular; 1781 } 1782 while (ptr != dd_base && *ptr != '/') 1783 ptr--; 1784 slash = ptr != result; 1785 } 1786 else 1787 { 1788 regular: 1789 /* Regular pathname component. */ 1790 if (slash) 1791 *ptr++ = '/'; 1792 memcpy (ptr, base, len); 1793 ptr += len; 1794 slash = 1; 1795 } 1796 1797 for (; IS_DIR_SEPARATOR (*probe); probe++) 1798 continue; 1799 } 1800 *ptr = 0; 1801 1802 return result; 1803 } 1804 1805 /* Generate an output file name. INPUT_NAME is the canonicalized main 1806 input file and SRC_NAME is the canonicalized file name. 1807 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With 1808 long_output_names we prepend the processed name of the input file 1809 to each output name (except when the current source file is the 1810 input file, so you don't get a double concatenation). The two 1811 components are separated by '##'. With preserve_paths we create a 1812 filename from all path components of the source file, replacing '/' 1813 with '#', and .. with '^', without it we simply take the basename 1814 component. (Remember, the canonicalized name will already have 1815 elided '.' components and converted \\ separators.) */ 1816 1817 static char * 1818 make_gcov_file_name (const char *input_name, const char *src_name) 1819 { 1820 char *ptr; 1821 char *result; 1822 1823 if (flag_long_names && input_name && strcmp (src_name, input_name)) 1824 { 1825 /* Generate the input filename part. */ 1826 result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10); 1827 1828 ptr = result; 1829 ptr = mangle_name (input_name, ptr); 1830 ptr[0] = ptr[1] = '#'; 1831 ptr += 2; 1832 } 1833 else 1834 { 1835 result = XNEWVEC (char, strlen (src_name) + 10); 1836 ptr = result; 1837 } 1838 1839 ptr = mangle_name (src_name, ptr); 1840 strcpy (ptr, ".gcov"); 1841 1842 return result; 1843 } 1844 1845 static char * 1846 mangle_name (char const *base, char *ptr) 1847 { 1848 size_t len; 1849 1850 /* Generate the source filename part. */ 1851 if (!flag_preserve_paths) 1852 { 1853 base = lbasename (base); 1854 len = strlen (base); 1855 memcpy (ptr, base, len); 1856 ptr += len; 1857 } 1858 else 1859 { 1860 /* Convert '/' to '#', convert '..' to '^', 1861 convert ':' to '~' on DOS based file system. */ 1862 const char *probe; 1863 1864 #if HAVE_DOS_BASED_FILE_SYSTEM 1865 if (base[0] && base[1] == ':') 1866 { 1867 ptr[0] = base[0]; 1868 ptr[1] = '~'; 1869 ptr += 2; 1870 base += 2; 1871 } 1872 #endif 1873 for (; *base; base = probe) 1874 { 1875 size_t len; 1876 1877 for (probe = base; *probe; probe++) 1878 if (*probe == '/') 1879 break; 1880 len = probe - base; 1881 if (len == 2 && base[0] == '.' && base[1] == '.') 1882 *ptr++ = '^'; 1883 else 1884 { 1885 memcpy (ptr, base, len); 1886 ptr += len; 1887 } 1888 if (*probe) 1889 { 1890 *ptr++ = '#'; 1891 probe++; 1892 } 1893 } 1894 } 1895 1896 return ptr; 1897 } 1898 1899 /* Scan through the bb_data for each line in the block, increment 1900 the line number execution count indicated by the execution count of 1901 the appropriate basic block. */ 1902 1903 static void 1904 add_line_counts (coverage_t *coverage, function_t *fn) 1905 { 1906 unsigned ix; 1907 line_t *line = NULL; /* This is propagated from one iteration to the 1908 next. */ 1909 1910 /* Scan each basic block. */ 1911 for (ix = 0; ix != fn->num_blocks; ix++) 1912 { 1913 block_t *block = &fn->blocks[ix]; 1914 unsigned *encoding; 1915 const source_t *src = NULL; 1916 unsigned jx; 1917 1918 if (block->count && ix && ix + 1 != fn->num_blocks) 1919 fn->blocks_executed++; 1920 for (jx = 0, encoding = block->u.line.encoding; 1921 jx != block->u.line.num; jx++, encoding++) 1922 if (!*encoding) 1923 { 1924 src = &sources[*++encoding]; 1925 jx++; 1926 } 1927 else 1928 { 1929 line = &src->lines[*encoding]; 1930 1931 if (coverage) 1932 { 1933 if (!line->exists) 1934 coverage->lines++; 1935 if (!line->count && block->count) 1936 coverage->lines_executed++; 1937 } 1938 line->exists = 1; 1939 if (!block->exceptional) 1940 line->unexceptional = 1; 1941 line->count += block->count; 1942 } 1943 free (block->u.line.encoding); 1944 block->u.cycle.arc = NULL; 1945 block->u.cycle.ident = ~0U; 1946 1947 if (!ix || ix + 1 == fn->num_blocks) 1948 /* Entry or exit block */; 1949 else if (flag_all_blocks) 1950 { 1951 line_t *block_line = line; 1952 1953 if (!block_line) 1954 block_line = &sources[fn->src].lines[fn->line]; 1955 1956 block->chain = block_line->u.blocks; 1957 block_line->u.blocks = block; 1958 } 1959 else if (flag_branches) 1960 { 1961 arc_t *arc; 1962 1963 for (arc = block->succ; arc; arc = arc->succ_next) 1964 { 1965 arc->line_next = line->u.branches; 1966 line->u.branches = arc; 1967 if (coverage && !arc->is_unconditional) 1968 add_branch_counts (coverage, arc); 1969 } 1970 } 1971 } 1972 if (!line) 1973 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name); 1974 } 1975 1976 /* Accumulate the line counts of a file. */ 1977 1978 static void 1979 accumulate_line_counts (source_t *src) 1980 { 1981 line_t *line; 1982 function_t *fn, *fn_p, *fn_n; 1983 unsigned ix; 1984 1985 /* Reverse the function order. */ 1986 for (fn = src->functions, fn_p = NULL; fn; 1987 fn_p = fn, fn = fn_n) 1988 { 1989 fn_n = fn->line_next; 1990 fn->line_next = fn_p; 1991 } 1992 src->functions = fn_p; 1993 1994 for (ix = src->num_lines, line = src->lines; ix--; line++) 1995 { 1996 if (!flag_all_blocks) 1997 { 1998 arc_t *arc, *arc_p, *arc_n; 1999 2000 /* Total and reverse the branch information. */ 2001 for (arc = line->u.branches, arc_p = NULL; arc; 2002 arc_p = arc, arc = arc_n) 2003 { 2004 arc_n = arc->line_next; 2005 arc->line_next = arc_p; 2006 2007 add_branch_counts (&src->coverage, arc); 2008 } 2009 line->u.branches = arc_p; 2010 } 2011 else if (line->u.blocks) 2012 { 2013 /* The user expects the line count to be the number of times 2014 a line has been executed. Simply summing the block count 2015 will give an artificially high number. The Right Thing 2016 is to sum the entry counts to the graph of blocks on this 2017 line, then find the elementary cycles of the local graph 2018 and add the transition counts of those cycles. */ 2019 block_t *block, *block_p, *block_n; 2020 gcov_type count = 0; 2021 2022 /* Reverse the block information. */ 2023 for (block = line->u.blocks, block_p = NULL; block; 2024 block_p = block, block = block_n) 2025 { 2026 block_n = block->chain; 2027 block->chain = block_p; 2028 block->u.cycle.ident = ix; 2029 } 2030 line->u.blocks = block_p; 2031 2032 /* Sum the entry arcs. */ 2033 for (block = line->u.blocks; block; block = block->chain) 2034 { 2035 arc_t *arc; 2036 2037 for (arc = block->pred; arc; arc = arc->pred_next) 2038 { 2039 if (arc->src->u.cycle.ident != ix) 2040 count += arc->count; 2041 if (flag_branches) 2042 add_branch_counts (&src->coverage, arc); 2043 } 2044 2045 /* Initialize the cs_count. */ 2046 for (arc = block->succ; arc; arc = arc->succ_next) 2047 arc->cs_count = arc->count; 2048 } 2049 2050 /* Find the loops. This uses the algorithm described in 2051 Tiernan 'An Efficient Search Algorithm to Find the 2052 Elementary Circuits of a Graph', CACM Dec 1970. We hold 2053 the P array by having each block point to the arc that 2054 connects to the previous block. The H array is implicitly 2055 held because of the arc ordering, and the block's 2056 previous arc pointer. 2057 2058 Although the algorithm is O(N^3) for highly connected 2059 graphs, at worst we'll have O(N^2), as most blocks have 2060 only one or two exits. Most graphs will be small. 2061 2062 For each loop we find, locate the arc with the smallest 2063 transition count, and add that to the cumulative 2064 count. Decrease flow over the cycle and remove the arc 2065 from consideration. */ 2066 for (block = line->u.blocks; block; block = block->chain) 2067 { 2068 block_t *head = block; 2069 arc_t *arc; 2070 2071 next_vertex:; 2072 arc = head->succ; 2073 current_vertex:; 2074 while (arc) 2075 { 2076 block_t *dst = arc->dst; 2077 if (/* Already used that arc. */ 2078 arc->cycle 2079 /* Not to same graph, or before first vertex. */ 2080 || dst->u.cycle.ident != ix 2081 /* Already in path. */ 2082 || dst->u.cycle.arc) 2083 { 2084 arc = arc->succ_next; 2085 continue; 2086 } 2087 2088 if (dst == block) 2089 { 2090 /* Found a closing arc. */ 2091 gcov_type cycle_count = arc->cs_count; 2092 arc_t *cycle_arc = arc; 2093 arc_t *probe_arc; 2094 2095 /* Locate the smallest arc count of the loop. */ 2096 for (dst = head; (probe_arc = dst->u.cycle.arc); 2097 dst = probe_arc->src) 2098 if (cycle_count > probe_arc->cs_count) 2099 { 2100 cycle_count = probe_arc->cs_count; 2101 cycle_arc = probe_arc; 2102 } 2103 2104 count += cycle_count; 2105 cycle_arc->cycle = 1; 2106 2107 /* Remove the flow from the cycle. */ 2108 arc->cs_count -= cycle_count; 2109 for (dst = head; (probe_arc = dst->u.cycle.arc); 2110 dst = probe_arc->src) 2111 probe_arc->cs_count -= cycle_count; 2112 2113 /* Unwind to the cyclic arc. */ 2114 while (head != cycle_arc->src) 2115 { 2116 arc = head->u.cycle.arc; 2117 head->u.cycle.arc = NULL; 2118 head = arc->src; 2119 } 2120 /* Move on. */ 2121 arc = arc->succ_next; 2122 continue; 2123 } 2124 2125 /* Add new block to chain. */ 2126 dst->u.cycle.arc = arc; 2127 head = dst; 2128 goto next_vertex; 2129 } 2130 /* We could not add another vertex to the path. Remove 2131 the last vertex from the list. */ 2132 arc = head->u.cycle.arc; 2133 if (arc) 2134 { 2135 /* It was not the first vertex. Move onto next arc. */ 2136 head->u.cycle.arc = NULL; 2137 head = arc->src; 2138 arc = arc->succ_next; 2139 goto current_vertex; 2140 } 2141 /* Mark this block as unusable. */ 2142 block->u.cycle.ident = ~0U; 2143 } 2144 2145 line->count = count; 2146 } 2147 2148 if (line->exists) 2149 { 2150 src->coverage.lines++; 2151 if (line->count) 2152 src->coverage.lines_executed++; 2153 } 2154 } 2155 } 2156 2157 /* Output information about ARC number IX. Returns nonzero if 2158 anything is output. */ 2159 2160 static int 2161 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) 2162 { 2163 if (arc->is_call_non_return) 2164 { 2165 if (arc->src->count) 2166 { 2167 fnotice (gcov_file, "call %2d returned %s\n", ix, 2168 format_gcov (arc->src->count - arc->count, 2169 arc->src->count, -flag_counts)); 2170 } 2171 else 2172 fnotice (gcov_file, "call %2d never executed\n", ix); 2173 } 2174 else if (!arc->is_unconditional) 2175 { 2176 if (arc->src->count) 2177 fnotice (gcov_file, "branch %2d taken %s%s\n", ix, 2178 format_gcov (arc->count, arc->src->count, -flag_counts), 2179 arc->fall_through ? " (fallthrough)" 2180 : arc->is_throw ? " (throw)" : ""); 2181 else 2182 fnotice (gcov_file, "branch %2d never executed\n", ix); 2183 } 2184 else if (flag_unconditional && !arc->dst->is_call_return) 2185 { 2186 if (arc->src->count) 2187 fnotice (gcov_file, "unconditional %2d taken %s\n", ix, 2188 format_gcov (arc->count, arc->src->count, -flag_counts)); 2189 else 2190 fnotice (gcov_file, "unconditional %2d never executed\n", ix); 2191 } 2192 else 2193 return 0; 2194 return 1; 2195 2196 } 2197 2198 static const char * 2199 read_line (FILE *file) 2200 { 2201 static char *string; 2202 static size_t string_len; 2203 size_t pos = 0; 2204 char *ptr; 2205 2206 if (!string_len) 2207 { 2208 string_len = 200; 2209 string = XNEWVEC (char, string_len); 2210 } 2211 2212 while ((ptr = fgets (string + pos, string_len - pos, file))) 2213 { 2214 size_t len = strlen (string + pos); 2215 2216 if (string[pos + len - 1] == '\n') 2217 { 2218 string[pos + len - 1] = 0; 2219 return string; 2220 } 2221 pos += len; 2222 ptr = XNEWVEC (char, string_len * 2); 2223 if (ptr) 2224 { 2225 memcpy (ptr, string, pos); 2226 string = ptr; 2227 string_len += 2; 2228 } 2229 else 2230 pos = 0; 2231 } 2232 2233 return pos ? string : NULL; 2234 } 2235 2236 /* Read in the source file one line at a time, and output that line to 2237 the gcov file preceded by its execution count and other 2238 information. */ 2239 2240 static void 2241 output_lines (FILE *gcov_file, const source_t *src) 2242 { 2243 FILE *source_file; 2244 unsigned line_num; /* current line number. */ 2245 const line_t *line; /* current line info ptr. */ 2246 const char *retval = ""; /* status of source file reading. */ 2247 function_t *fn = NULL; 2248 2249 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name); 2250 if (!multiple_files) 2251 { 2252 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name); 2253 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, 2254 no_data_file ? "-" : da_file_name); 2255 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs); 2256 } 2257 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count); 2258 2259 source_file = fopen (src->name, "r"); 2260 if (!source_file) 2261 { 2262 fnotice (stderr, "Cannot open source file %s\n", src->name); 2263 retval = NULL; 2264 } 2265 else if (src->file_time == 0) 2266 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0); 2267 2268 if (flag_branches) 2269 fn = src->functions; 2270 2271 for (line_num = 1, line = &src->lines[line_num]; 2272 line_num < src->num_lines; line_num++, line++) 2273 { 2274 for (; fn && fn->line == line_num; fn = fn->line_next) 2275 { 2276 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred; 2277 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count; 2278 2279 for (; arc; arc = arc->pred_next) 2280 if (arc->fake) 2281 return_count -= arc->count; 2282 2283 fprintf (gcov_file, "function %s", fn->name); 2284 fprintf (gcov_file, " called %s", 2285 format_gcov (fn->blocks[0].count, 0, -1)); 2286 fprintf (gcov_file, " returned %s", 2287 format_gcov (return_count, fn->blocks[0].count, 0)); 2288 fprintf (gcov_file, " blocks executed %s", 2289 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0)); 2290 fprintf (gcov_file, "\n"); 2291 } 2292 2293 if (retval) 2294 retval = read_line (source_file); 2295 2296 /* For lines which don't exist in the .bb file, print '-' before 2297 the source line. For lines which exist but were never 2298 executed, print '#####' or '=====' before the source line. 2299 Otherwise, print the execution count before the source line. 2300 There are 16 spaces of indentation added before the source 2301 line so that tabs won't be messed up. */ 2302 fprintf (gcov_file, "%9s:%5u:%s\n", 2303 !line->exists ? "-" : line->count 2304 ? format_gcov (line->count, 0, -1) 2305 : line->unexceptional ? "#####" : "=====", line_num, 2306 retval ? retval : "/*EOF*/"); 2307 2308 if (flag_all_blocks) 2309 { 2310 block_t *block; 2311 arc_t *arc; 2312 int ix, jx; 2313 2314 for (ix = jx = 0, block = line->u.blocks; block; 2315 block = block->chain) 2316 { 2317 if (!block->is_call_return) 2318 fprintf (gcov_file, "%9s:%5u-block %2d\n", 2319 !line->exists ? "-" : block->count 2320 ? format_gcov (block->count, 0, -1) 2321 : block->exceptional ? "%%%%%" : "$$$$$", 2322 line_num, ix++); 2323 if (flag_branches) 2324 for (arc = block->succ; arc; arc = arc->succ_next) 2325 jx += output_branch_count (gcov_file, jx, arc); 2326 } 2327 } 2328 else if (flag_branches) 2329 { 2330 int ix; 2331 arc_t *arc; 2332 2333 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next) 2334 ix += output_branch_count (gcov_file, ix, arc); 2335 } 2336 } 2337 2338 /* Handle all remaining source lines. There may be lines after the 2339 last line of code. */ 2340 if (retval) 2341 { 2342 for (; (retval = read_line (source_file)); line_num++) 2343 fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval); 2344 } 2345 2346 if (source_file) 2347 fclose (source_file); 2348 } 2349