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