gcov.c revision 161651
1176348Smarcel/* Gcov.c: prepend line execution counts and branch probabilities to a 2176348Smarcel source file. 3176348Smarcel Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 4176348Smarcel 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 5176348Smarcel Contributed by James E. Wilson of Cygnus Support. 6176348Smarcel Mangled by Bob Manson of Cygnus Support. 7176348Smarcel Mangled further by Nathan Sidwell <nathan@codesourcery.com> 8176348Smarcel 9176348SmarcelGcov is free software; you can redistribute it and/or modify 10176348Smarcelit under the terms of the GNU General Public License as published by 11176348Smarcelthe Free Software Foundation; either version 2, or (at your option) 12176348Smarcelany later version. 13176348Smarcel 14176348SmarcelGcov is distributed in the hope that it will be useful, 15176348Smarcelbut WITHOUT ANY WARRANTY; without even the implied warranty of 16176348SmarcelMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17176348SmarcelGNU General Public License for more details. 18176348Smarcel 19176348SmarcelYou should have received a copy of the GNU General Public License 20176348Smarcelalong with Gcov; see the file COPYING. If not, write to 21176348Smarcelthe Free Software Foundation, 59 Temple Place - Suite 330, 22176348SmarcelBoston, MA 02111-1307, USA. */ 23176348Smarcel 24176348Smarcel/* ??? Print a list of the ten blocks with the highest execution counts, 25176348Smarcel and list the line numbers corresponding to those blocks. Also, perhaps 26176348Smarcel list the line numbers with the highest execution counts, only printing 27176348Smarcel the first if there are several which are all listed in the same block. */ 28176348Smarcel 29176348Smarcel/* ??? Should have an option to print the number of basic blocks, and the 30176348Smarcel percent of them that are covered. */ 31176348Smarcel 32176348Smarcel/* ??? Does not correctly handle the case where two .bb files refer to 33176348Smarcel the same included source file. For example, if one has a short 34176348Smarcel file containing only inline functions, which is then included in 35176348Smarcel two other files, then there will be two .bb files which refer to 36176348Smarcel the include file, but there is no way to get the total execution 37176348Smarcel counts for the included file, can only get execution counts for one 38176348Smarcel or the other of the including files. this can be fixed by --ratios 39176348Smarcel --long-file-names --preserve-paths and perl. */ 40176348Smarcel 41176348Smarcel/* Need an option to show individual block counts, and show 42176348Smarcel probabilities of fall through arcs. */ 43176348Smarcel 44176348Smarcel#include "config.h" 45176348Smarcel#include "system.h" 46176348Smarcel#include "coretypes.h" 47176348Smarcel#include "tm.h" 48176348Smarcel#include "intl.h" 49176348Smarcel#include "version.h" 50176348Smarcel#undef abort 51176348Smarcel 52176348Smarcel#include <getopt.h> 53176348Smarcel 54176348Smarcel#define IN_GCOV 1 55176348Smarcel#include "gcov-io.h" 56176348Smarcel#include "gcov-io.c" 57176348Smarcel 58176348Smarcel/* The bbg file is generated by -ftest-coverage option. The da file is 59176348Smarcel generated by a program compiled with -fprofile-arcs. Their formats 60176348Smarcel are documented in gcov-io.h. */ 61176348Smarcel 62/* The functions in this file for creating and solution program flow graphs 63 are very similar to functions in the gcc source file profile.c. In 64 some places we make use of the knowledge of how profile.c works to 65 select particular algorithms here. */ 66 67/* This is the size of the buffer used to read in source file lines. */ 68 69#define STRING_SIZE 200 70 71struct function_info; 72struct block_info; 73struct source_info; 74 75/* Describes an arc between two basic blocks. */ 76 77typedef struct arc_info 78{ 79 /* source and destination blocks. */ 80 struct block_info *src; 81 struct block_info *dst; 82 83 /* transition counts. */ 84 gcov_type count; 85 /* used in cycle search, so that we do not clobber original counts. */ 86 gcov_type cs_count; 87 88 unsigned int count_valid : 1; 89 unsigned int on_tree : 1; 90 unsigned int fake : 1; 91 unsigned int fall_through : 1; 92 93 /* Arc is for a function that abnormally returns. */ 94 unsigned int is_call_non_return : 1; 95 96 /* Arc is for catch/setjump. */ 97 unsigned int is_nonlocal_return : 1; 98 99 /* Is an unconditional branch. */ 100 unsigned int is_unconditional : 1; 101 102 /* Loop making arc. */ 103 unsigned int cycle : 1; 104 105 /* Next branch on line. */ 106 struct arc_info *line_next; 107 108 /* Links to next arc on src and dst lists. */ 109 struct arc_info *succ_next; 110 struct arc_info *pred_next; 111} arc_t; 112 113/* Describes a basic block. Contains lists of arcs to successor and 114 predecessor blocks. */ 115 116typedef struct block_info 117{ 118 /* Chain of exit and entry arcs. */ 119 arc_t *succ; 120 arc_t *pred; 121 122 /* Number of unprocessed exit and entry arcs. */ 123 gcov_type num_succ; 124 gcov_type num_pred; 125 126 /* Block execution count. */ 127 gcov_type count; 128 unsigned flags : 13; 129 unsigned count_valid : 1; 130 unsigned valid_chain : 1; 131 unsigned invalid_chain : 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 169typedef struct function_info 170{ 171 /* Name of function. */ 172 char *name; 173 unsigned ident; 174 unsigned checksum; 175 176 /* Array of basic blocks. */ 177 block_t *blocks; 178 unsigned num_blocks; 179 unsigned blocks_executed; 180 181 /* Raw arc coverage counts. */ 182 gcov_type *counts; 183 unsigned num_counts; 184 185 /* First line number. */ 186 unsigned line; 187 struct source_info *src; 188 189 /* Next function in same source file. */ 190 struct function_info *line_next; 191 192 /* Next function. */ 193 struct function_info *next; 194} function_t; 195 196/* Describes coverage of a file or function. */ 197 198typedef struct coverage_info 199{ 200 int lines; 201 int lines_executed; 202 203 int branches; 204 int branches_executed; 205 int branches_taken; 206 207 int calls; 208 int calls_executed; 209 210 char *name; 211} coverage_t; 212 213/* Describes a single line of source. Contains a chain of basic blocks 214 with code on it. */ 215 216typedef struct line_info 217{ 218 gcov_type count; /* execution count */ 219 union 220 { 221 arc_t *branches; /* branches from blocks that end on this 222 line. Used for branch-counts when not 223 all-blocks mode. */ 224 block_t *blocks; /* blocks which start on this line. Used 225 in all-blocks mode. */ 226 } u; 227 unsigned exists : 1; 228} line_t; 229 230/* Describes a file mentioned in the block graph. Contains an array 231 of line info. */ 232 233typedef struct source_info 234{ 235 /* Name of source file. */ 236 char *name; 237 unsigned index; 238 239 /* Array of line information. */ 240 line_t *lines; 241 unsigned num_lines; 242 243 coverage_t coverage; 244 245 /* Functions in this source file. These are in ascending line 246 number order. */ 247 function_t *functions; 248 249 /* Next source file. */ 250 struct source_info *next; 251} source_t; 252 253/* Holds a list of function basic block graphs. */ 254 255static function_t *functions; 256 257/* This points to the head of the sourcefile structure list. */ 258 259static source_t *sources; 260 261/* This holds data summary information. */ 262 263static struct gcov_summary object_summary; 264static unsigned program_count; 265 266/* Modification time of graph file. */ 267 268static time_t bbg_file_time; 269 270/* Name and file pointer of the input file for the basic block graph. */ 271 272static char *bbg_file_name; 273 274/* Stamp of the bbg file */ 275static unsigned bbg_stamp; 276 277/* Name and file pointer of the input file for the arc count data. */ 278 279static char *da_file_name; 280 281/* Output branch probabilities. */ 282 283static int flag_branches = 0; 284 285/* Show unconditional branches too. */ 286static int flag_unconditional = 0; 287 288/* Output a gcov file if this is true. This is on by default, and can 289 be turned off by the -n option. */ 290 291static int flag_gcov_file = 1; 292 293/* For included files, make the gcov output file name include the name 294 of the input source file. For example, if x.h is included in a.c, 295 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ 296 297static int flag_long_names = 0; 298 299/* Output count information for every basic block, not merely those 300 that contain line number information. */ 301 302static int flag_all_blocks = 0; 303 304/* Output summary info for each function. */ 305 306static int flag_function_summary = 0; 307 308/* Object directory file prefix. This is the directory/file where the 309 graph and data files are looked for, if nonzero. */ 310 311static char *object_directory = 0; 312 313/* Preserve all pathname components. Needed when object files and 314 source files are in subdirectories. '/' is mangled as '#', '.' is 315 elided and '..' mangled to '^'. */ 316 317static int flag_preserve_paths = 0; 318 319/* Output the number of times a branch was taken as opposed to the percentage 320 of times it was taken. */ 321 322static int flag_counts = 0; 323 324/* Forward declarations. */ 325static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; 326static int process_args (int, char **); 327static void print_usage (int) ATTRIBUTE_NORETURN; 328static void print_version (void) ATTRIBUTE_NORETURN; 329static void process_file (const char *); 330static void create_file_names (const char *); 331static source_t *find_source (const char *); 332static int read_graph_file (void); 333static int read_count_file (void); 334static void solve_flow_graph (function_t *); 335static void add_branch_counts (coverage_t *, const arc_t *); 336static void add_line_counts (coverage_t *, function_t *); 337static void function_summary (const coverage_t *, const char *); 338static const char *format_gcov (gcov_type, gcov_type, int); 339static void accumulate_line_counts (source_t *); 340static int output_branch_count (FILE *, int, const arc_t *); 341static void output_lines (FILE *, const source_t *); 342static char *make_gcov_file_name (const char *, const char *); 343static void release_structures (void); 344extern int main (int, char **); 345 346int 347main (int argc, char **argv) 348{ 349 int argno; 350 351 gcc_init_libintl (); 352 353 argno = process_args (argc, argv); 354 if (optind == argc) 355 print_usage (true); 356 357 for (; argno != argc; argno++) 358 { 359 release_structures (); 360 361 process_file (argv[argno]); 362 } 363 364 return 0; 365} 366 367static void 368fnotice (FILE *file, const char *msgid, ...) 369{ 370 va_list ap; 371 372 va_start (ap, msgid); 373 vfprintf (file, _(msgid), ap); 374 va_end (ap); 375} 376 377/* More 'friendly' abort that prints the line and file. 378 config.h can #define abort fancy_abort if you like that sort of thing. */ 379extern void fancy_abort (void) ATTRIBUTE_NORETURN; 380 381void 382fancy_abort (void) 383{ 384 fnotice (stderr, "Internal gcov abort.\n"); 385 exit (FATAL_EXIT_CODE); 386} 387 388/* Print a usage message and exit. If ERROR_P is nonzero, this is an error, 389 otherwise the output of --help. */ 390 391static void 392print_usage (int error_p) 393{ 394 FILE *file = error_p ? stderr : stdout; 395 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 396 397 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n"); 398 fnotice (file, "Print code coverage information.\n\n"); 399 fnotice (file, " -h, --help Print this help, then exit\n"); 400 fnotice (file, " -v, --version Print version number, then exit\n"); 401 fnotice (file, " -a, --all-blocks Show information for every basic block\n"); 402 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n"); 403 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\ 404 rather than percentages\n"); 405 fnotice (file, " -n, --no-output Do not create an output file\n"); 406 fnotice (file, " -l, --long-file-names Use long output file names for included\n\ 407 source files\n"); 408 fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 409 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); 410 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); 411 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); 412 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", 413 bug_report_url); 414 exit (status); 415} 416 417/* Print version information and exit. */ 418 419static void 420print_version (void) 421{ 422 fnotice (stdout, "gcov (GCC) %s\n", version_string); 423 fprintf (stdout, "Copyright %s 2006 Free Software Foundation, Inc.\n", 424 _("(C)")); 425 fnotice (stdout, 426 _("This is free software; see the source for copying conditions.\n" 427 "There is NO warranty; not even for MERCHANTABILITY or \n" 428 "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 429 exit (SUCCESS_EXIT_CODE); 430} 431 432static const struct option options[] = 433{ 434 { "help", no_argument, NULL, 'h' }, 435 { "version", no_argument, NULL, 'v' }, 436 { "all-blocks", no_argument, NULL, 'a' }, 437 { "branch-probabilities", no_argument, NULL, 'b' }, 438 { "branch-counts", no_argument, NULL, 'c' }, 439 { "no-output", no_argument, NULL, 'n' }, 440 { "long-file-names", no_argument, NULL, 'l' }, 441 { "function-summaries", no_argument, NULL, 'f' }, 442 { "preserve-paths", no_argument, NULL, 'p' }, 443 { "object-directory", required_argument, NULL, 'o' }, 444 { "object-file", required_argument, NULL, 'o' }, 445 { "unconditional-branches", no_argument, NULL, 'u' }, 446 { 0, 0, 0, 0 } 447}; 448 449/* Process args, return index to first non-arg. */ 450 451static int 452process_args (int argc, char **argv) 453{ 454 int opt; 455 456 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1) 457 { 458 switch (opt) 459 { 460 case 'a': 461 flag_all_blocks = 1; 462 break; 463 case 'b': 464 flag_branches = 1; 465 break; 466 case 'c': 467 flag_counts = 1; 468 break; 469 case 'f': 470 flag_function_summary = 1; 471 break; 472 case 'h': 473 print_usage (false); 474 /* print_usage will exit. */ 475 case 'l': 476 flag_long_names = 1; 477 break; 478 case 'n': 479 flag_gcov_file = 0; 480 break; 481 case 'o': 482 object_directory = optarg; 483 break; 484 case 'p': 485 flag_preserve_paths = 1; 486 break; 487 case 'u': 488 flag_unconditional = 1; 489 break; 490 case 'v': 491 print_version (); 492 /* print_version will exit. */ 493 default: 494 print_usage (true); 495 /* print_usage will exit. */ 496 } 497 } 498 499 return optind; 500} 501 502/* Process a single source file. */ 503 504static void 505process_file (const char *file_name) 506{ 507 source_t *src; 508 function_t *fn; 509 510 create_file_names (file_name); 511 if (read_graph_file ()) 512 return; 513 514 if (!functions) 515 { 516 fnotice (stderr, "%s:no functions found\n", bbg_file_name); 517 return; 518 } 519 520 if (read_count_file ()) 521 return; 522 523 for (fn = functions; fn; fn = fn->next) 524 solve_flow_graph (fn); 525 for (src = sources; src; src = src->next) 526 src->lines = xcalloc (src->num_lines, sizeof (line_t)); 527 for (fn = functions; fn; fn = fn->next) 528 { 529 coverage_t coverage; 530 531 memset (&coverage, 0, sizeof (coverage)); 532 coverage.name = fn->name; 533 add_line_counts (flag_function_summary ? &coverage : NULL, fn); 534 if (flag_function_summary) 535 { 536 function_summary (&coverage, "Function"); 537 fnotice (stdout, "\n"); 538 } 539 } 540 541 for (src = sources; src; src = src->next) 542 { 543 accumulate_line_counts (src); 544 function_summary (&src->coverage, "File"); 545 if (flag_gcov_file) 546 { 547 char *gcov_file_name = make_gcov_file_name (file_name, src->name); 548 FILE *gcov_file = fopen (gcov_file_name, "w"); 549 550 if (gcov_file) 551 { 552 fnotice (stdout, "%s:creating `%s'\n", 553 src->name, gcov_file_name); 554 output_lines (gcov_file, src); 555 if (ferror (gcov_file)) 556 fnotice (stderr, "%s:error writing output file `%s'\n", 557 src->name, gcov_file_name); 558 fclose (gcov_file); 559 } 560 else 561 fnotice (stderr, "%s:could not open output file `%s'\n", 562 src->name, gcov_file_name); 563 free (gcov_file_name); 564 } 565 fnotice (stdout, "\n"); 566 } 567} 568 569/* Release all memory used. */ 570 571static void 572release_structures (void) 573{ 574 function_t *fn; 575 source_t *src; 576 577 free (bbg_file_name); 578 free (da_file_name); 579 da_file_name = bbg_file_name = NULL; 580 bbg_file_time = 0; 581 bbg_stamp = 0; 582 583 while ((src = sources)) 584 { 585 sources = src->next; 586 587 free (src->name); 588 free (src->lines); 589 } 590 591 while ((fn = functions)) 592 { 593 unsigned ix; 594 block_t *block; 595 596 functions = fn->next; 597 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++) 598 { 599 arc_t *arc, *arc_n; 600 601 for (arc = block->succ; arc; arc = arc_n) 602 { 603 arc_n = arc->succ_next; 604 free (arc); 605 } 606 } 607 free (fn->blocks); 608 free (fn->counts); 609 } 610} 611 612/* Generate the names of the graph and data files. If OBJECT_DIRECTORY 613 is not specified, these are looked for in the current directory, 614 and named from the basename of the FILE_NAME sans extension. If 615 OBJECT_DIRECTORY is specified and is a directory, the files are in 616 that directory, but named from the basename of the FILE_NAME, sans 617 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of 618 the object *file*, and the data files are named from that. */ 619 620static void 621create_file_names (const char *file_name) 622{ 623 char *cptr; 624 char *name; 625 int length = strlen (file_name); 626 int base; 627 628 if (object_directory && object_directory[0]) 629 { 630 struct stat status; 631 632 length += strlen (object_directory) + 2; 633 name = xmalloc (length); 634 name[0] = 0; 635 636 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); 637 strcat (name, object_directory); 638 if (base && name[strlen (name) - 1] != '/') 639 strcat (name, "/"); 640 } 641 else 642 { 643 name = xmalloc (length + 1); 644 name[0] = 0; 645 base = 1; 646 } 647 648 if (base) 649 { 650 /* Append source file name. */ 651 cptr = strrchr (file_name, '/'); 652 strcat (name, cptr ? cptr + 1 : file_name); 653 } 654 655 /* Remove the extension. */ 656 cptr = strrchr (name, '.'); 657 if (cptr) 658 *cptr = 0; 659 660 length = strlen (name); 661 662 bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1); 663 strcpy (bbg_file_name, name); 664 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); 665 666 da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1); 667 strcpy (da_file_name, name); 668 strcpy (da_file_name + length, GCOV_DATA_SUFFIX); 669 670 return; 671} 672 673/* Find or create a source file structure for FILE_NAME. Copies 674 FILE_NAME on creation */ 675 676static source_t * 677find_source (const char *file_name) 678{ 679 source_t *src; 680 681 if (!file_name) 682 file_name = "<unknown>"; 683 684 for (src = sources; src; src = src->next) 685 if (!strcmp (file_name, src->name)) 686 return src; 687 688 src = xcalloc (1, sizeof (source_t)); 689 src->name = xstrdup (file_name); 690 src->coverage.name = src->name; 691 src->index = sources ? sources->index + 1 : 1; 692 src->next = sources; 693 sources = src; 694 695 return src; 696} 697 698/* Read the graph file. Return nonzero on fatal error. */ 699 700static int 701read_graph_file (void) 702{ 703 unsigned version; 704 unsigned current_tag = 0; 705 struct function_info *fn = NULL; 706 source_t *src = NULL; 707 unsigned ix; 708 unsigned tag; 709 710 if (!gcov_open (bbg_file_name, 1)) 711 { 712 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name); 713 return 1; 714 } 715 bbg_file_time = gcov_time (); 716 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) 717 { 718 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name); 719 gcov_close (); 720 return 1; 721 } 722 723 version = gcov_read_unsigned (); 724 if (version != GCOV_VERSION) 725 { 726 char v[4], e[4]; 727 728 GCOV_UNSIGNED2STRING (v, version); 729 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 730 731 fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n", 732 bbg_file_name, v, e); 733 } 734 bbg_stamp = gcov_read_unsigned (); 735 736 while ((tag = gcov_read_unsigned ())) 737 { 738 unsigned length = gcov_read_unsigned (); 739 gcov_position_t base = gcov_position (); 740 741 if (tag == GCOV_TAG_FUNCTION) 742 { 743 char *function_name; 744 unsigned ident, checksum, lineno; 745 source_t *src; 746 function_t *probe, *prev; 747 748 ident = gcov_read_unsigned (); 749 checksum = gcov_read_unsigned (); 750 function_name = xstrdup (gcov_read_string ()); 751 src = find_source (gcov_read_string ()); 752 lineno = gcov_read_unsigned (); 753 754 fn = xcalloc (1, sizeof (function_t)); 755 fn->name = function_name; 756 fn->ident = ident; 757 fn->checksum = checksum; 758 fn->src = src; 759 fn->line = lineno; 760 761 fn->next = functions; 762 functions = fn; 763 current_tag = tag; 764 765 if (lineno >= src->num_lines) 766 src->num_lines = lineno + 1; 767 /* Now insert it into the source file's list of 768 functions. Normally functions will be encountered in 769 ascending order, so a simple scan is quick. */ 770 for (probe = src->functions, prev = NULL; 771 probe && probe->line > lineno; 772 prev = probe, probe = probe->line_next) 773 continue; 774 fn->line_next = probe; 775 if (prev) 776 prev->line_next = fn; 777 else 778 src->functions = fn; 779 } 780 else if (fn && tag == GCOV_TAG_BLOCKS) 781 { 782 if (fn->blocks) 783 fnotice (stderr, "%s:already seen blocks for `%s'\n", 784 bbg_file_name, fn->name); 785 else 786 { 787 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length); 788 fn->num_blocks = num_blocks; 789 790 fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t)); 791 for (ix = 0; ix != num_blocks; ix++) 792 fn->blocks[ix].flags = gcov_read_unsigned (); 793 } 794 } 795 else if (fn && tag == GCOV_TAG_ARCS) 796 { 797 unsigned src = gcov_read_unsigned (); 798 unsigned num_dests = GCOV_TAG_ARCS_NUM (length); 799 800 if (src >= fn->num_blocks || fn->blocks[src].succ) 801 goto corrupt; 802 803 while (num_dests--) 804 { 805 struct arc_info *arc; 806 unsigned dest = gcov_read_unsigned (); 807 unsigned flags = gcov_read_unsigned (); 808 809 if (dest >= fn->num_blocks) 810 goto corrupt; 811 arc = xcalloc (1, sizeof (arc_t)); 812 813 arc->dst = &fn->blocks[dest]; 814 arc->src = &fn->blocks[src]; 815 816 arc->count = 0; 817 arc->count_valid = 0; 818 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); 819 arc->fake = !!(flags & GCOV_ARC_FAKE); 820 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); 821 822 arc->succ_next = fn->blocks[src].succ; 823 fn->blocks[src].succ = arc; 824 fn->blocks[src].num_succ++; 825 826 arc->pred_next = fn->blocks[dest].pred; 827 fn->blocks[dest].pred = arc; 828 fn->blocks[dest].num_pred++; 829 830 if (arc->fake) 831 { 832 if (src) 833 { 834 /* Exceptional exit from this function, the 835 source block must be a call. */ 836 fn->blocks[src].is_call_site = 1; 837 arc->is_call_non_return = 1; 838 } 839 else 840 { 841 /* Non-local return from a callee of this 842 function. The destination block is a catch or 843 setjmp. */ 844 arc->is_nonlocal_return = 1; 845 fn->blocks[dest].is_nonlocal_return = 1; 846 } 847 } 848 849 if (!arc->on_tree) 850 fn->num_counts++; 851 } 852 } 853 else if (fn && tag == GCOV_TAG_LINES) 854 { 855 unsigned blockno = gcov_read_unsigned (); 856 unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned)); 857 858 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding) 859 goto corrupt; 860 861 for (ix = 0; ; ) 862 { 863 unsigned lineno = gcov_read_unsigned (); 864 865 if (lineno) 866 { 867 if (!ix) 868 { 869 line_nos[ix++] = 0; 870 line_nos[ix++] = src->index; 871 } 872 line_nos[ix++] = lineno; 873 if (lineno >= src->num_lines) 874 src->num_lines = lineno + 1; 875 } 876 else 877 { 878 const char *file_name = gcov_read_string (); 879 880 if (!file_name) 881 break; 882 src = find_source (file_name); 883 884 line_nos[ix++] = 0; 885 line_nos[ix++] = src->index; 886 } 887 } 888 889 fn->blocks[blockno].u.line.encoding = line_nos; 890 fn->blocks[blockno].u.line.num = ix; 891 } 892 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) 893 { 894 fn = NULL; 895 current_tag = 0; 896 } 897 gcov_sync (base, length); 898 if (gcov_is_error ()) 899 break; 900 } 901 if (!gcov_is_eof ()) 902 { 903 corrupt:; 904 fnotice (stderr, "%s:corrupted\n", bbg_file_name); 905 gcov_close (); 906 return 1; 907 } 908 gcov_close (); 909 910 /* We built everything backwards, so nreverse them all. */ 911 912 /* Reverse sources. Not strictly necessary, but we'll then process 913 them in the 'expected' order. */ 914 { 915 source_t *src, *src_p, *src_n; 916 917 for (src_p = NULL, src = sources; src; src_p = src, src = src_n) 918 { 919 src_n = src->next; 920 src->next = src_p; 921 } 922 sources = src_p; 923 } 924 925 /* Reverse functions. */ 926 { 927 function_t *fn, *fn_p, *fn_n; 928 929 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n) 930 { 931 unsigned ix; 932 933 fn_n = fn->next; 934 fn->next = fn_p; 935 936 /* Reverse the arcs. */ 937 for (ix = fn->num_blocks; ix--;) 938 { 939 arc_t *arc, *arc_p, *arc_n; 940 941 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; 942 arc_p = arc, arc = arc_n) 943 { 944 arc_n = arc->succ_next; 945 arc->succ_next = arc_p; 946 } 947 fn->blocks[ix].succ = arc_p; 948 949 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc; 950 arc_p = arc, arc = arc_n) 951 { 952 arc_n = arc->pred_next; 953 arc->pred_next = arc_p; 954 } 955 fn->blocks[ix].pred = arc_p; 956 } 957 } 958 functions = fn_p; 959 } 960 return 0; 961} 962 963/* Reads profiles from the count file and attach to each 964 function. Return nonzero if fatal error. */ 965 966static int 967read_count_file (void) 968{ 969 unsigned ix; 970 unsigned version; 971 unsigned tag; 972 function_t *fn = NULL; 973 int error = 0; 974 975 if (!gcov_open (da_file_name, 1)) 976 { 977 fnotice (stderr, "%s:cannot open data file\n", da_file_name); 978 return 1; 979 } 980 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) 981 { 982 fnotice (stderr, "%s:not a gcov data file\n", da_file_name); 983 cleanup:; 984 gcov_close (); 985 return 1; 986 } 987 version = gcov_read_unsigned (); 988 if (version != GCOV_VERSION) 989 { 990 char v[4], e[4]; 991 992 GCOV_UNSIGNED2STRING (v, version); 993 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 994 995 fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n", 996 da_file_name, v, e); 997 } 998 tag = gcov_read_unsigned (); 999 if (tag != bbg_stamp) 1000 { 1001 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name); 1002 goto cleanup; 1003 } 1004 1005 while ((tag = gcov_read_unsigned ())) 1006 { 1007 unsigned length = gcov_read_unsigned (); 1008 unsigned long base = gcov_position (); 1009 1010 if (tag == GCOV_TAG_OBJECT_SUMMARY) 1011 gcov_read_summary (&object_summary); 1012 else if (tag == GCOV_TAG_PROGRAM_SUMMARY) 1013 program_count++; 1014 else if (tag == GCOV_TAG_FUNCTION) 1015 { 1016 unsigned ident = gcov_read_unsigned (); 1017 struct function_info *fn_n = functions; 1018 1019 for (fn = fn ? fn->next : NULL; ; fn = fn->next) 1020 { 1021 if (fn) 1022 ; 1023 else if ((fn = fn_n)) 1024 fn_n = NULL; 1025 else 1026 { 1027 fnotice (stderr, "%s:unknown function `%u'\n", 1028 da_file_name, ident); 1029 break; 1030 } 1031 if (fn->ident == ident) 1032 break; 1033 } 1034 1035 if (!fn) 1036 ; 1037 else if (gcov_read_unsigned () != fn->checksum) 1038 { 1039 mismatch:; 1040 fnotice (stderr, "%s:profile mismatch for `%s'\n", 1041 da_file_name, fn->name); 1042 goto cleanup; 1043 } 1044 } 1045 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) 1046 { 1047 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) 1048 goto mismatch; 1049 1050 if (!fn->counts) 1051 fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type)); 1052 1053 for (ix = 0; ix != fn->num_counts; ix++) 1054 fn->counts[ix] += gcov_read_counter (); 1055 } 1056 gcov_sync (base, length); 1057 if ((error = gcov_is_error ())) 1058 break; 1059 } 1060 1061 if (!gcov_is_eof ()) 1062 { 1063 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", 1064 da_file_name); 1065 goto cleanup; 1066 } 1067 1068 gcov_close (); 1069 return 0; 1070} 1071 1072/* Solve the flow graph. Propagate counts from the instrumented arcs 1073 to the blocks and the uninstrumented arcs. */ 1074 1075static void 1076solve_flow_graph (function_t *fn) 1077{ 1078 unsigned ix; 1079 arc_t *arc; 1080 gcov_type *count_ptr = fn->counts; 1081 block_t *blk; 1082 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ 1083 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ 1084 1085 if (fn->num_blocks < 2) 1086 fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n", 1087 bbg_file_name, fn->name); 1088 else 1089 { 1090 if (fn->blocks[0].num_pred) 1091 fnotice (stderr, "%s:`%s' has arcs to entry block\n", 1092 bbg_file_name, fn->name); 1093 else 1094 /* We can't deduce the entry block counts from the lack of 1095 predecessors. */ 1096 fn->blocks[0].num_pred = ~(unsigned)0; 1097 1098 if (fn->blocks[fn->num_blocks - 1].num_succ) 1099 fnotice (stderr, "%s:`%s' has arcs from exit block\n", 1100 bbg_file_name, fn->name); 1101 else 1102 /* Likewise, we can't deduce exit block counts from the lack 1103 of its successors. */ 1104 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0; 1105 } 1106 1107 /* Propagate the measured counts, this must be done in the same 1108 order as the code in profile.c */ 1109 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++) 1110 { 1111 block_t const *prev_dst = NULL; 1112 int out_of_order = 0; 1113 int non_fake_succ = 0; 1114 1115 for (arc = blk->succ; arc; arc = arc->succ_next) 1116 { 1117 if (!arc->fake) 1118 non_fake_succ++; 1119 1120 if (!arc->on_tree) 1121 { 1122 if (count_ptr) 1123 arc->count = *count_ptr++; 1124 arc->count_valid = 1; 1125 blk->num_succ--; 1126 arc->dst->num_pred--; 1127 } 1128 if (prev_dst && prev_dst > arc->dst) 1129 out_of_order = 1; 1130 prev_dst = arc->dst; 1131 } 1132 if (non_fake_succ == 1) 1133 { 1134 /* If there is only one non-fake exit, it is an 1135 unconditional branch. */ 1136 for (arc = blk->succ; arc; arc = arc->succ_next) 1137 if (!arc->fake) 1138 { 1139 arc->is_unconditional = 1; 1140 /* If this block is instrumenting a call, it might be 1141 an artificial block. It is not artificial if it has 1142 a non-fallthrough exit, or the destination of this 1143 arc has more than one entry. Mark the destination 1144 block as a return site, if none of those conditions 1145 hold. */ 1146 if (blk->is_call_site && arc->fall_through 1147 && arc->dst->pred == arc && !arc->pred_next) 1148 arc->dst->is_call_return = 1; 1149 } 1150 } 1151 1152 /* Sort the successor arcs into ascending dst order. profile.c 1153 normally produces arcs in the right order, but sometimes with 1154 one or two out of order. We're not using a particularly 1155 smart sort. */ 1156 if (out_of_order) 1157 { 1158 arc_t *start = blk->succ; 1159 unsigned changes = 1; 1160 1161 while (changes) 1162 { 1163 arc_t *arc, *arc_p, *arc_n; 1164 1165 changes = 0; 1166 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) 1167 { 1168 if (arc->dst > arc_n->dst) 1169 { 1170 changes = 1; 1171 if (arc_p) 1172 arc_p->succ_next = arc_n; 1173 else 1174 start = arc_n; 1175 arc->succ_next = arc_n->succ_next; 1176 arc_n->succ_next = arc; 1177 arc_p = arc_n; 1178 } 1179 else 1180 { 1181 arc_p = arc; 1182 arc = arc_n; 1183 } 1184 } 1185 } 1186 blk->succ = start; 1187 } 1188 1189 /* Place it on the invalid chain, it will be ignored if that's 1190 wrong. */ 1191 blk->invalid_chain = 1; 1192 blk->chain = invalid_blocks; 1193 invalid_blocks = blk; 1194 } 1195 1196 while (invalid_blocks || valid_blocks) 1197 { 1198 while ((blk = invalid_blocks)) 1199 { 1200 gcov_type total = 0; 1201 const arc_t *arc; 1202 1203 invalid_blocks = blk->chain; 1204 blk->invalid_chain = 0; 1205 if (!blk->num_succ) 1206 for (arc = blk->succ; arc; arc = arc->succ_next) 1207 total += arc->count; 1208 else if (!blk->num_pred) 1209 for (arc = blk->pred; arc; arc = arc->pred_next) 1210 total += arc->count; 1211 else 1212 continue; 1213 1214 blk->count = total; 1215 blk->count_valid = 1; 1216 blk->chain = valid_blocks; 1217 blk->valid_chain = 1; 1218 valid_blocks = blk; 1219 } 1220 while ((blk = valid_blocks)) 1221 { 1222 gcov_type total; 1223 arc_t *arc, *inv_arc; 1224 1225 valid_blocks = blk->chain; 1226 blk->valid_chain = 0; 1227 if (blk->num_succ == 1) 1228 { 1229 block_t *dst; 1230 1231 total = blk->count; 1232 inv_arc = NULL; 1233 for (arc = blk->succ; arc; arc = arc->succ_next) 1234 { 1235 total -= arc->count; 1236 if (!arc->count_valid) 1237 inv_arc = arc; 1238 } 1239 dst = inv_arc->dst; 1240 inv_arc->count_valid = 1; 1241 inv_arc->count = total; 1242 blk->num_succ--; 1243 dst->num_pred--; 1244 if (dst->count_valid) 1245 { 1246 if (dst->num_pred == 1 && !dst->valid_chain) 1247 { 1248 dst->chain = valid_blocks; 1249 dst->valid_chain = 1; 1250 valid_blocks = dst; 1251 } 1252 } 1253 else 1254 { 1255 if (!dst->num_pred && !dst->invalid_chain) 1256 { 1257 dst->chain = invalid_blocks; 1258 dst->invalid_chain = 1; 1259 invalid_blocks = dst; 1260 } 1261 } 1262 } 1263 if (blk->num_pred == 1) 1264 { 1265 block_t *src; 1266 1267 total = blk->count; 1268 inv_arc = NULL; 1269 for (arc = blk->pred; arc; arc = arc->pred_next) 1270 { 1271 total -= arc->count; 1272 if (!arc->count_valid) 1273 inv_arc = arc; 1274 } 1275 src = inv_arc->src; 1276 inv_arc->count_valid = 1; 1277 inv_arc->count = total; 1278 blk->num_pred--; 1279 src->num_succ--; 1280 if (src->count_valid) 1281 { 1282 if (src->num_succ == 1 && !src->valid_chain) 1283 { 1284 src->chain = valid_blocks; 1285 src->valid_chain = 1; 1286 valid_blocks = src; 1287 } 1288 } 1289 else 1290 { 1291 if (!src->num_succ && !src->invalid_chain) 1292 { 1293 src->chain = invalid_blocks; 1294 src->invalid_chain = 1; 1295 invalid_blocks = src; 1296 } 1297 } 1298 } 1299 } 1300 } 1301 1302 /* If the graph has been correctly solved, every block will have a 1303 valid count. */ 1304 for (ix = 0; ix < fn->num_blocks; ix++) 1305 if (!fn->blocks[ix].count_valid) 1306 { 1307 fnotice (stderr, "%s:graph is unsolvable for `%s'\n", 1308 bbg_file_name, fn->name); 1309 break; 1310 } 1311} 1312 1313 1314 1315/* Increment totals in COVERAGE according to arc ARC. */ 1316 1317static void 1318add_branch_counts (coverage_t *coverage, const arc_t *arc) 1319{ 1320 if (arc->is_call_non_return) 1321 { 1322 coverage->calls++; 1323 if (arc->src->count) 1324 coverage->calls_executed++; 1325 } 1326 else if (!arc->is_unconditional) 1327 { 1328 coverage->branches++; 1329 if (arc->src->count) 1330 coverage->branches_executed++; 1331 if (arc->count) 1332 coverage->branches_taken++; 1333 } 1334} 1335 1336/* Format a HOST_WIDE_INT as either a percent ratio, or absolute 1337 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. 1338 If DP is zero, no decimal point is printed. Only print 100% when 1339 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply 1340 format TOP. Return pointer to a static string. */ 1341 1342static char const * 1343format_gcov (gcov_type top, gcov_type bottom, int dp) 1344{ 1345 static char buffer[20]; 1346 1347 if (dp >= 0) 1348 { 1349 float ratio = bottom ? (float)top / bottom : 0; 1350 int ix; 1351 unsigned limit = 100; 1352 unsigned percent; 1353 1354 for (ix = dp; ix--; ) 1355 limit *= 10; 1356 1357 percent = (unsigned) (ratio * limit + (float)0.5); 1358 if (percent <= 0 && top) 1359 percent = 1; 1360 else if (percent >= limit && top != bottom) 1361 percent = limit - 1; 1362 ix = sprintf (buffer, "%.*u%%", dp + 1, percent); 1363 if (dp) 1364 { 1365 dp++; 1366 do 1367 { 1368 buffer[ix+1] = buffer[ix]; 1369 ix--; 1370 } 1371 while (dp--); 1372 buffer[ix + 1] = '.'; 1373 } 1374 } 1375 else 1376 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top); 1377 1378 return buffer; 1379} 1380 1381 1382/* Output summary info for a function. */ 1383 1384static void 1385function_summary (const coverage_t *coverage, const char *title) 1386{ 1387 fnotice (stdout, "%s `%s'\n", title, coverage->name); 1388 1389 if (coverage->lines) 1390 fnotice (stdout, "Lines executed:%s of %d\n", 1391 format_gcov (coverage->lines_executed, coverage->lines, 2), 1392 coverage->lines); 1393 else 1394 fnotice (stdout, "No executable lines"); 1395 1396 if (flag_branches) 1397 { 1398 if (coverage->branches) 1399 { 1400 fnotice (stdout, "Branches executed:%s of %d\n", 1401 format_gcov (coverage->branches_executed, 1402 coverage->branches, 2), 1403 coverage->branches); 1404 fnotice (stdout, "Taken at least once:%s of %d\n", 1405 format_gcov (coverage->branches_taken, 1406 coverage->branches, 2), 1407 coverage->branches); 1408 } 1409 else 1410 fnotice (stdout, "No branches\n"); 1411 if (coverage->calls) 1412 fnotice (stdout, "Calls executed:%s of %d\n", 1413 format_gcov (coverage->calls_executed, coverage->calls, 2), 1414 coverage->calls); 1415 else 1416 fnotice (stdout, "No calls\n"); 1417 } 1418} 1419 1420/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS 1421 affect name generation. With preserve_paths we create a filename 1422 from all path components of the source file, replacing '/' with 1423 '#', without it we simply take the basename component. With 1424 long_output_names we prepend the processed name of the input file 1425 to each output name (except when the current source file is the 1426 input file, so you don't get a double concatenation). The two 1427 components are separated by '##'. Also '.' filename components are 1428 removed and '..' components are renamed to '^'. */ 1429 1430static char * 1431make_gcov_file_name (const char *input_name, const char *src_name) 1432{ 1433 char *cptr; 1434 char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10); 1435 1436 name[0] = 0; 1437 if (flag_long_names && strcmp (src_name, input_name)) 1438 { 1439 /* Generate the input filename part. */ 1440 cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/'); 1441 strcat (name, cptr ? cptr + 1 : input_name); 1442 strcat (name, "##"); 1443 } 1444 1445 /* Generate the source filename part. */ 1446 cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/'); 1447 strcat (name, cptr ? cptr + 1 : src_name); 1448 1449 if (flag_preserve_paths) 1450 { 1451 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */ 1452 char *prev; 1453 1454 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));) 1455 { 1456 unsigned shift = 0; 1457 1458 if (prev + 1 == cptr && prev[0] == '.') 1459 { 1460 /* Remove '.' */ 1461 shift = 2; 1462 } 1463 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.') 1464 { 1465 /* Convert '..' */ 1466 shift = 1; 1467 prev[1] = '^'; 1468 } 1469 else 1470 *cptr++ = '#'; 1471 if (shift) 1472 { 1473 cptr = prev; 1474 do 1475 prev[0] = prev[shift]; 1476 while (*prev++); 1477 } 1478 } 1479 } 1480 1481 strcat (name, ".gcov"); 1482 return name; 1483} 1484 1485/* Scan through the bb_data for each line in the block, increment 1486 the line number execution count indicated by the execution count of 1487 the appropriate basic block. */ 1488 1489static void 1490add_line_counts (coverage_t *coverage, function_t *fn) 1491{ 1492 unsigned ix; 1493 line_t *line = NULL; /* This is propagated from one iteration to the 1494 next. */ 1495 1496 /* Scan each basic block. */ 1497 for (ix = 0; ix != fn->num_blocks; ix++) 1498 { 1499 block_t *block = &fn->blocks[ix]; 1500 unsigned *encoding; 1501 const source_t *src = NULL; 1502 unsigned jx; 1503 1504 if (block->count && ix && ix + 1 != fn->num_blocks) 1505 fn->blocks_executed++; 1506 for (jx = 0, encoding = block->u.line.encoding; 1507 jx != block->u.line.num; jx++, encoding++) 1508 if (!*encoding) 1509 { 1510 unsigned src_n = *++encoding; 1511 1512 for (src = sources; src->index != src_n; src = src->next) 1513 continue; 1514 jx++; 1515 } 1516 else 1517 { 1518 line = &src->lines[*encoding]; 1519 1520 if (coverage) 1521 { 1522 if (!line->exists) 1523 coverage->lines++; 1524 if (!line->count && block->count) 1525 coverage->lines_executed++; 1526 } 1527 line->exists = 1; 1528 line->count += block->count; 1529 } 1530 free (block->u.line.encoding); 1531 block->u.cycle.arc = NULL; 1532 block->u.cycle.ident = ~0U; 1533 1534 if (!ix || ix + 1 == fn->num_blocks) 1535 /* Entry or exit block */; 1536 else if (flag_all_blocks) 1537 { 1538 line_t *block_line = line ? line : &fn->src->lines[fn->line]; 1539 1540 block->chain = block_line->u.blocks; 1541 block_line->u.blocks = block; 1542 } 1543 else if (flag_branches) 1544 { 1545 arc_t *arc; 1546 1547 for (arc = block->succ; arc; arc = arc->succ_next) 1548 { 1549 arc->line_next = line->u.branches; 1550 line->u.branches = arc; 1551 if (coverage && !arc->is_unconditional) 1552 add_branch_counts (coverage, arc); 1553 } 1554 } 1555 } 1556 if (!line) 1557 fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name); 1558} 1559 1560/* Accumulate the line counts of a file. */ 1561 1562static void 1563accumulate_line_counts (source_t *src) 1564{ 1565 line_t *line; 1566 function_t *fn, *fn_p, *fn_n; 1567 unsigned ix; 1568 1569 /* Reverse the function order. */ 1570 for (fn = src->functions, fn_p = NULL; fn; 1571 fn_p = fn, fn = fn_n) 1572 { 1573 fn_n = fn->line_next; 1574 fn->line_next = fn_p; 1575 } 1576 src->functions = fn_p; 1577 1578 for (ix = src->num_lines, line = src->lines; ix--; line++) 1579 { 1580 if (!flag_all_blocks) 1581 { 1582 arc_t *arc, *arc_p, *arc_n; 1583 1584 /* Total and reverse the branch information. */ 1585 for (arc = line->u.branches, arc_p = NULL; arc; 1586 arc_p = arc, arc = arc_n) 1587 { 1588 arc_n = arc->line_next; 1589 arc->line_next = arc_p; 1590 1591 add_branch_counts (&src->coverage, arc); 1592 } 1593 line->u.branches = arc_p; 1594 } 1595 else if (line->u.blocks) 1596 { 1597 /* The user expects the line count to be the number of times 1598 a line has been executed. Simply summing the block count 1599 will give an artificially high number. The Right Thing 1600 is to sum the entry counts to the graph of blocks on this 1601 line, then find the elementary cycles of the local graph 1602 and add the transition counts of those cycles. */ 1603 block_t *block, *block_p, *block_n; 1604 gcov_type count = 0; 1605 1606 /* Reverse the block information. */ 1607 for (block = line->u.blocks, block_p = NULL; block; 1608 block_p = block, block = block_n) 1609 { 1610 block_n = block->chain; 1611 block->chain = block_p; 1612 block->u.cycle.ident = ix; 1613 } 1614 line->u.blocks = block_p; 1615 1616 /* Sum the entry arcs. */ 1617 for (block = line->u.blocks; block; block = block->chain) 1618 { 1619 arc_t *arc; 1620 1621 for (arc = block->pred; arc; arc = arc->pred_next) 1622 { 1623 if (arc->src->u.cycle.ident != ix) 1624 count += arc->count; 1625 if (flag_branches) 1626 add_branch_counts (&src->coverage, arc); 1627 } 1628 1629 /* Initialize the cs_count. */ 1630 for (arc = block->succ; arc; arc = arc->succ_next) 1631 arc->cs_count = arc->count; 1632 } 1633 1634 /* Find the loops. This uses the algorithm described in 1635 Tiernan 'An Efficient Search Algorithm to Find the 1636 Elementary Circuits of a Graph', CACM Dec 1970. We hold 1637 the P array by having each block point to the arc that 1638 connects to the previous block. The H array is implicitly 1639 held because of the arc ordering, and the block's 1640 previous arc pointer. 1641 1642 Although the algorithm is O(N^3) for highly connected 1643 graphs, at worst we'll have O(N^2), as most blocks have 1644 only one or two exits. Most graphs will be small. 1645 1646 For each loop we find, locate the arc with the smallest 1647 transition count, and add that to the cumulative 1648 count. Decrease flow over the cycle and remove the arc 1649 from consideration. */ 1650 for (block = line->u.blocks; block; block = block->chain) 1651 { 1652 block_t *head = block; 1653 arc_t *arc; 1654 1655 next_vertex:; 1656 arc = head->succ; 1657 current_vertex:; 1658 while (arc) 1659 { 1660 block_t *dst = arc->dst; 1661 if (/* Already used that arc. */ 1662 arc->cycle 1663 /* Not to same graph, or before first vertex. */ 1664 || dst->u.cycle.ident != ix 1665 /* Already in path. */ 1666 || dst->u.cycle.arc) 1667 { 1668 arc = arc->succ_next; 1669 continue; 1670 } 1671 1672 if (dst == block) 1673 { 1674 /* Found a closing arc. */ 1675 gcov_type cycle_count = arc->cs_count; 1676 arc_t *cycle_arc = arc; 1677 arc_t *probe_arc; 1678 1679 /* Locate the smallest arc count of the loop. */ 1680 for (dst = head; (probe_arc = dst->u.cycle.arc); 1681 dst = probe_arc->src) 1682 if (cycle_count > probe_arc->cs_count) 1683 { 1684 cycle_count = probe_arc->cs_count; 1685 cycle_arc = probe_arc; 1686 } 1687 1688 count += cycle_count; 1689 cycle_arc->cycle = 1; 1690 1691 /* Remove the flow from the cycle. */ 1692 arc->cs_count -= cycle_count; 1693 for (dst = head; (probe_arc = dst->u.cycle.arc); 1694 dst = probe_arc->src) 1695 probe_arc->cs_count -= cycle_count; 1696 1697 /* Unwind to the cyclic arc. */ 1698 while (head != cycle_arc->src) 1699 { 1700 arc = head->u.cycle.arc; 1701 head->u.cycle.arc = NULL; 1702 head = arc->src; 1703 } 1704 /* Move on. */ 1705 arc = arc->succ_next; 1706 continue; 1707 } 1708 1709 /* Add new block to chain. */ 1710 dst->u.cycle.arc = arc; 1711 head = dst; 1712 goto next_vertex; 1713 } 1714 /* We could not add another vertex to the path. Remove 1715 the last vertex from the list. */ 1716 arc = head->u.cycle.arc; 1717 if (arc) 1718 { 1719 /* It was not the first vertex. Move onto next arc. */ 1720 head->u.cycle.arc = NULL; 1721 head = arc->src; 1722 arc = arc->succ_next; 1723 goto current_vertex; 1724 } 1725 /* Mark this block as unusable. */ 1726 block->u.cycle.ident = ~0U; 1727 } 1728 1729 line->count = count; 1730 } 1731 1732 if (line->exists) 1733 { 1734 src->coverage.lines++; 1735 if (line->count) 1736 src->coverage.lines_executed++; 1737 } 1738 } 1739} 1740 1741/* Ouput information about ARC number IX. Returns nonzero if 1742 anything is output. */ 1743 1744static int 1745output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) 1746{ 1747 1748 if (arc->is_call_non_return) 1749 { 1750 if (arc->src->count) 1751 { 1752 fnotice (gcov_file, "call %2d returned %s\n", ix, 1753 format_gcov (arc->src->count - arc->count, 1754 arc->src->count, -flag_counts)); 1755 } 1756 else 1757 fnotice (gcov_file, "call %2d never executed\n", ix); 1758 } 1759 else if (!arc->is_unconditional) 1760 { 1761 if (arc->src->count) 1762 fnotice (gcov_file, "branch %2d taken %s%s\n", ix, 1763 format_gcov (arc->count, arc->src->count, -flag_counts), 1764 arc->fall_through ? " (fallthrough)" : ""); 1765 else 1766 fnotice (gcov_file, "branch %2d never executed\n", ix); 1767 } 1768 else if (flag_unconditional && !arc->dst->is_call_return) 1769 { 1770 if (arc->src->count) 1771 fnotice (gcov_file, "unconditional %2d taken %s\n", ix, 1772 format_gcov (arc->count, arc->src->count, -flag_counts)); 1773 else 1774 fnotice (gcov_file, "unconditional %2d never executed\n", ix); 1775 } 1776 else 1777 return 0; 1778 return 1; 1779 1780} 1781 1782/* Read in the source file one line at a time, and output that line to 1783 the gcov file preceded by its execution count and other 1784 information. */ 1785 1786static void 1787output_lines (FILE *gcov_file, const source_t *src) 1788{ 1789 FILE *source_file; 1790 unsigned line_num; /* current line number. */ 1791 const line_t *line; /* current line info ptr. */ 1792 char string[STRING_SIZE]; /* line buffer. */ 1793 char const *retval = ""; /* status of source file reading. */ 1794 function_t *fn = src->functions; 1795 1796 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name); 1797 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name); 1798 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name); 1799 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, 1800 object_summary.ctrs[GCOV_COUNTER_ARCS].runs); 1801 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count); 1802 1803 source_file = fopen (src->name, "r"); 1804 if (!source_file) 1805 { 1806 fnotice (stderr, "%s:cannot open source file\n", src->name); 1807 retval = NULL; 1808 } 1809 else 1810 { 1811 struct stat status; 1812 1813 if (!fstat (fileno (source_file), &status) 1814 && status.st_mtime > bbg_file_time) 1815 { 1816 fnotice (stderr, "%s:source file is newer than graph file `%s'\n", 1817 src->name, bbg_file_name); 1818 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", 1819 "-", 0); 1820 } 1821 } 1822 1823 for (line_num = 1, line = &src->lines[line_num]; 1824 line_num < src->num_lines; line_num++, line++) 1825 { 1826 for (; fn && fn->line == line_num; fn = fn->line_next) 1827 { 1828 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred; 1829 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count; 1830 1831 for (; arc; arc = arc->pred_next) 1832 if (arc->fake) 1833 return_count -= arc->count; 1834 1835 fprintf (gcov_file, "function %s", fn->name); 1836 fprintf (gcov_file, " called %s", 1837 format_gcov (fn->blocks[0].count, 0, -1)); 1838 fprintf (gcov_file, " returned %s", 1839 format_gcov (return_count, fn->blocks[0].count, 0)); 1840 fprintf (gcov_file, " blocks executed %s", 1841 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0)); 1842 fprintf (gcov_file, "\n"); 1843 } 1844 1845 /* For lines which don't exist in the .bb file, print '-' before 1846 the source line. For lines which exist but were never 1847 executed, print '#####' before the source line. Otherwise, 1848 print the execution count before the source line. There are 1849 16 spaces of indentation added before the source line so that 1850 tabs won't be messed up. */ 1851 fprintf (gcov_file, "%9s:%5u:", 1852 !line->exists ? "-" : !line->count ? "#####" 1853 : format_gcov (line->count, 0, -1), line_num); 1854 1855 if (retval) 1856 { 1857 /* Copy source line. */ 1858 do 1859 { 1860 retval = fgets (string, STRING_SIZE, source_file); 1861 if (!retval) 1862 break; 1863 fputs (retval, gcov_file); 1864 } 1865 while (!retval[0] || retval[strlen (retval) - 1] != '\n'); 1866 } 1867 if (!retval) 1868 fputs ("/*EOF*/\n", gcov_file); 1869 1870 if (flag_all_blocks) 1871 { 1872 block_t *block; 1873 arc_t *arc; 1874 int ix, jx; 1875 1876 for (ix = jx = 0, block = line->u.blocks; block; 1877 block = block->chain) 1878 { 1879 if (!block->is_call_return) 1880 fprintf (gcov_file, "%9s:%5u-block %2d\n", 1881 !line->exists ? "-" : !block->count ? "$$$$$" 1882 : format_gcov (block->count, 0, -1), 1883 line_num, ix++); 1884 if (flag_branches) 1885 for (arc = block->succ; arc; arc = arc->succ_next) 1886 jx += output_branch_count (gcov_file, jx, arc); 1887 } 1888 } 1889 else if (flag_branches) 1890 { 1891 int ix; 1892 arc_t *arc; 1893 1894 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next) 1895 ix += output_branch_count (gcov_file, ix, arc); 1896 } 1897 } 1898 1899 /* Handle all remaining source lines. There may be lines after the 1900 last line of code. */ 1901 if (retval) 1902 { 1903 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++) 1904 { 1905 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval); 1906 1907 while (!retval[0] || retval[strlen (retval) - 1] != '\n') 1908 { 1909 retval = fgets (string, STRING_SIZE, source_file); 1910 if (!retval) 1911 break; 1912 fputs (retval, gcov_file); 1913 } 1914 } 1915 } 1916 1917 if (source_file) 1918 fclose (source_file); 1919} 1920