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