1*38fd1498Szrj /* Gcov.c: prepend line execution counts and branch probabilities to a 2*38fd1498Szrj source file. 3*38fd1498Szrj Copyright (C) 1990-2018 Free Software Foundation, Inc. 4*38fd1498Szrj Contributed by James E. Wilson of Cygnus Support. 5*38fd1498Szrj Mangled by Bob Manson of Cygnus Support. 6*38fd1498Szrj Mangled further by Nathan Sidwell <nathan@codesourcery.com> 7*38fd1498Szrj 8*38fd1498Szrj Gcov is free software; you can redistribute it and/or modify 9*38fd1498Szrj it under the terms of the GNU General Public License as published by 10*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option) 11*38fd1498Szrj any later version. 12*38fd1498Szrj 13*38fd1498Szrj Gcov is distributed in the hope that it will be useful, 14*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of 15*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*38fd1498Szrj GNU General Public License for more details. 17*38fd1498Szrj 18*38fd1498Szrj You should have received a copy of the GNU General Public License 19*38fd1498Szrj along with Gcov; see the file COPYING3. If not see 20*38fd1498Szrj <http://www.gnu.org/licenses/>. */ 21*38fd1498Szrj 22*38fd1498Szrj /* ??? Print a list of the ten blocks with the highest execution counts, 23*38fd1498Szrj and list the line numbers corresponding to those blocks. Also, perhaps 24*38fd1498Szrj list the line numbers with the highest execution counts, only printing 25*38fd1498Szrj the first if there are several which are all listed in the same block. */ 26*38fd1498Szrj 27*38fd1498Szrj /* ??? Should have an option to print the number of basic blocks, and the 28*38fd1498Szrj percent of them that are covered. */ 29*38fd1498Szrj 30*38fd1498Szrj /* Need an option to show individual block counts, and show 31*38fd1498Szrj probabilities of fall through arcs. */ 32*38fd1498Szrj 33*38fd1498Szrj #include "config.h" 34*38fd1498Szrj #define INCLUDE_ALGORITHM 35*38fd1498Szrj #define INCLUDE_VECTOR 36*38fd1498Szrj #define INCLUDE_STRING 37*38fd1498Szrj #define INCLUDE_MAP 38*38fd1498Szrj #define INCLUDE_SET 39*38fd1498Szrj #include "system.h" 40*38fd1498Szrj #include "coretypes.h" 41*38fd1498Szrj #include "tm.h" 42*38fd1498Szrj #include "intl.h" 43*38fd1498Szrj #include "diagnostic.h" 44*38fd1498Szrj #include "version.h" 45*38fd1498Szrj #include "demangle.h" 46*38fd1498Szrj #include "color-macros.h" 47*38fd1498Szrj 48*38fd1498Szrj #include <getopt.h> 49*38fd1498Szrj 50*38fd1498Szrj #include "md5.h" 51*38fd1498Szrj 52*38fd1498Szrj using namespace std; 53*38fd1498Szrj 54*38fd1498Szrj #define IN_GCOV 1 55*38fd1498Szrj #include "gcov-io.h" 56*38fd1498Szrj #include "gcov-io.c" 57*38fd1498Szrj 58*38fd1498Szrj /* The gcno file is generated by -ftest-coverage option. The gcda file is 59*38fd1498Szrj generated by a program compiled with -fprofile-arcs. Their formats 60*38fd1498Szrj are documented in gcov-io.h. */ 61*38fd1498Szrj 62*38fd1498Szrj /* The functions in this file for creating and solution program flow graphs 63*38fd1498Szrj are very similar to functions in the gcc source file profile.c. In 64*38fd1498Szrj some places we make use of the knowledge of how profile.c works to 65*38fd1498Szrj select particular algorithms here. */ 66*38fd1498Szrj 67*38fd1498Szrj /* The code validates that the profile information read in corresponds 68*38fd1498Szrj to the code currently being compiled. Rather than checking for 69*38fd1498Szrj identical files, the code below compares a checksum on the CFG 70*38fd1498Szrj (based on the order of basic blocks and the arcs in the CFG). If 71*38fd1498Szrj the CFG checksum in the gcda file match the CFG checksum in the 72*38fd1498Szrj gcno file, the profile data will be used. */ 73*38fd1498Szrj 74*38fd1498Szrj /* This is the size of the buffer used to read in source file lines. */ 75*38fd1498Szrj 76*38fd1498Szrj struct function_info; 77*38fd1498Szrj struct block_info; 78*38fd1498Szrj struct source_info; 79*38fd1498Szrj 80*38fd1498Szrj /* Describes an arc between two basic blocks. */ 81*38fd1498Szrj 82*38fd1498Szrj struct arc_info 83*38fd1498Szrj { 84*38fd1498Szrj /* source and destination blocks. */ 85*38fd1498Szrj struct block_info *src; 86*38fd1498Szrj struct block_info *dst; 87*38fd1498Szrj 88*38fd1498Szrj /* transition counts. */ 89*38fd1498Szrj gcov_type count; 90*38fd1498Szrj /* used in cycle search, so that we do not clobber original counts. */ 91*38fd1498Szrj gcov_type cs_count; 92*38fd1498Szrj 93*38fd1498Szrj unsigned int count_valid : 1; 94*38fd1498Szrj unsigned int on_tree : 1; 95*38fd1498Szrj unsigned int fake : 1; 96*38fd1498Szrj unsigned int fall_through : 1; 97*38fd1498Szrj 98*38fd1498Szrj /* Arc to a catch handler. */ 99*38fd1498Szrj unsigned int is_throw : 1; 100*38fd1498Szrj 101*38fd1498Szrj /* Arc is for a function that abnormally returns. */ 102*38fd1498Szrj unsigned int is_call_non_return : 1; 103*38fd1498Szrj 104*38fd1498Szrj /* Arc is for catch/setjmp. */ 105*38fd1498Szrj unsigned int is_nonlocal_return : 1; 106*38fd1498Szrj 107*38fd1498Szrj /* Is an unconditional branch. */ 108*38fd1498Szrj unsigned int is_unconditional : 1; 109*38fd1498Szrj 110*38fd1498Szrj /* Loop making arc. */ 111*38fd1498Szrj unsigned int cycle : 1; 112*38fd1498Szrj 113*38fd1498Szrj /* Links to next arc on src and dst lists. */ 114*38fd1498Szrj struct arc_info *succ_next; 115*38fd1498Szrj struct arc_info *pred_next; 116*38fd1498Szrj }; 117*38fd1498Szrj 118*38fd1498Szrj /* Describes which locations (lines and files) are associated with 119*38fd1498Szrj a basic block. */ 120*38fd1498Szrj 121*38fd1498Szrj struct block_location_info 122*38fd1498Szrj { 123*38fd1498Szrj block_location_info (unsigned _source_file_idx): 124*38fd1498Szrj source_file_idx (_source_file_idx) 125*38fd1498Szrj {} 126*38fd1498Szrj 127*38fd1498Szrj unsigned source_file_idx; 128*38fd1498Szrj vector<unsigned> lines; 129*38fd1498Szrj }; 130*38fd1498Szrj 131*38fd1498Szrj /* Describes a basic block. Contains lists of arcs to successor and 132*38fd1498Szrj predecessor blocks. */ 133*38fd1498Szrj 134*38fd1498Szrj struct block_info 135*38fd1498Szrj { 136*38fd1498Szrj /* Constructor. */ 137*38fd1498Szrj block_info (); 138*38fd1498Szrj 139*38fd1498Szrj /* Chain of exit and entry arcs. */ 140*38fd1498Szrj arc_info *succ; 141*38fd1498Szrj arc_info *pred; 142*38fd1498Szrj 143*38fd1498Szrj /* Number of unprocessed exit and entry arcs. */ 144*38fd1498Szrj gcov_type num_succ; 145*38fd1498Szrj gcov_type num_pred; 146*38fd1498Szrj 147*38fd1498Szrj unsigned id; 148*38fd1498Szrj 149*38fd1498Szrj /* Block execution count. */ 150*38fd1498Szrj gcov_type count; 151*38fd1498Szrj unsigned count_valid : 1; 152*38fd1498Szrj unsigned valid_chain : 1; 153*38fd1498Szrj unsigned invalid_chain : 1; 154*38fd1498Szrj unsigned exceptional : 1; 155*38fd1498Szrj 156*38fd1498Szrj /* Block is a call instrumenting site. */ 157*38fd1498Szrj unsigned is_call_site : 1; /* Does the call. */ 158*38fd1498Szrj unsigned is_call_return : 1; /* Is the return. */ 159*38fd1498Szrj 160*38fd1498Szrj /* Block is a landing pad for longjmp or throw. */ 161*38fd1498Szrj unsigned is_nonlocal_return : 1; 162*38fd1498Szrj 163*38fd1498Szrj vector<block_location_info> locations; 164*38fd1498Szrj 165*38fd1498Szrj struct 166*38fd1498Szrj { 167*38fd1498Szrj /* Single line graph cycle workspace. Used for all-blocks 168*38fd1498Szrj mode. */ 169*38fd1498Szrj arc_info *arc; 170*38fd1498Szrj unsigned ident; 171*38fd1498Szrj } cycle; /* Used in all-blocks mode, after blocks are linked onto 172*38fd1498Szrj lines. */ 173*38fd1498Szrj 174*38fd1498Szrj /* Temporary chain for solving graph, and for chaining blocks on one 175*38fd1498Szrj line. */ 176*38fd1498Szrj struct block_info *chain; 177*38fd1498Szrj 178*38fd1498Szrj }; 179*38fd1498Szrj 180*38fd1498Szrj block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0), 181*38fd1498Szrj id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0), 182*38fd1498Szrj exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0), 183*38fd1498Szrj locations (), chain (NULL) 184*38fd1498Szrj { 185*38fd1498Szrj cycle.arc = NULL; 186*38fd1498Szrj } 187*38fd1498Szrj 188*38fd1498Szrj /* Describes a single line of source. Contains a chain of basic blocks 189*38fd1498Szrj with code on it. */ 190*38fd1498Szrj 191*38fd1498Szrj struct line_info 192*38fd1498Szrj { 193*38fd1498Szrj /* Default constructor. */ 194*38fd1498Szrj line_info (); 195*38fd1498Szrj 196*38fd1498Szrj /* Return true when NEEDLE is one of basic blocks the line belongs to. */ 197*38fd1498Szrj bool has_block (block_info *needle); 198*38fd1498Szrj 199*38fd1498Szrj /* Execution count. */ 200*38fd1498Szrj gcov_type count; 201*38fd1498Szrj 202*38fd1498Szrj /* Branches from blocks that end on this line. */ 203*38fd1498Szrj vector<arc_info *> branches; 204*38fd1498Szrj 205*38fd1498Szrj /* blocks which start on this line. Used in all-blocks mode. */ 206*38fd1498Szrj vector<block_info *> blocks; 207*38fd1498Szrj 208*38fd1498Szrj unsigned exists : 1; 209*38fd1498Szrj unsigned unexceptional : 1; 210*38fd1498Szrj unsigned has_unexecuted_block : 1; 211*38fd1498Szrj }; 212*38fd1498Szrj 213*38fd1498Szrj line_info::line_info (): count (0), branches (), blocks (), exists (false), 214*38fd1498Szrj unexceptional (0), has_unexecuted_block (0) 215*38fd1498Szrj { 216*38fd1498Szrj } 217*38fd1498Szrj 218*38fd1498Szrj bool 219*38fd1498Szrj line_info::has_block (block_info *needle) 220*38fd1498Szrj { 221*38fd1498Szrj return std::find (blocks.begin (), blocks.end (), needle) != blocks.end (); 222*38fd1498Szrj } 223*38fd1498Szrj 224*38fd1498Szrj /* Describes a single function. Contains an array of basic blocks. */ 225*38fd1498Szrj 226*38fd1498Szrj struct function_info 227*38fd1498Szrj { 228*38fd1498Szrj function_info (); 229*38fd1498Szrj ~function_info (); 230*38fd1498Szrj 231*38fd1498Szrj /* Return true when line N belongs to the function in source file SRC_IDX. 232*38fd1498Szrj The line must be defined in body of the function, can't be inlined. */ 233*38fd1498Szrj bool group_line_p (unsigned n, unsigned src_idx); 234*38fd1498Szrj 235*38fd1498Szrj /* Function filter based on function_info::artificial variable. */ 236*38fd1498Szrj 237*38fd1498Szrj static inline bool 238*38fd1498Szrj is_artificial (function_info *fn) 239*38fd1498Szrj { 240*38fd1498Szrj return fn->artificial; 241*38fd1498Szrj } 242*38fd1498Szrj 243*38fd1498Szrj /* Name of function. */ 244*38fd1498Szrj char *name; 245*38fd1498Szrj char *demangled_name; 246*38fd1498Szrj unsigned ident; 247*38fd1498Szrj unsigned lineno_checksum; 248*38fd1498Szrj unsigned cfg_checksum; 249*38fd1498Szrj 250*38fd1498Szrj /* The graph contains at least one fake incoming edge. */ 251*38fd1498Szrj unsigned has_catch : 1; 252*38fd1498Szrj 253*38fd1498Szrj /* True when the function is artificial and does not exist 254*38fd1498Szrj in a source file. */ 255*38fd1498Szrj unsigned artificial : 1; 256*38fd1498Szrj 257*38fd1498Szrj /* True when multiple functions start at a line in a source file. */ 258*38fd1498Szrj unsigned is_group : 1; 259*38fd1498Szrj 260*38fd1498Szrj /* Array of basic blocks. Like in GCC, the entry block is 261*38fd1498Szrj at blocks[0] and the exit block is at blocks[1]. */ 262*38fd1498Szrj #define ENTRY_BLOCK (0) 263*38fd1498Szrj #define EXIT_BLOCK (1) 264*38fd1498Szrj vector<block_info> blocks; 265*38fd1498Szrj unsigned blocks_executed; 266*38fd1498Szrj 267*38fd1498Szrj /* Raw arc coverage counts. */ 268*38fd1498Szrj vector<gcov_type> counts; 269*38fd1498Szrj 270*38fd1498Szrj /* First line number. */ 271*38fd1498Szrj unsigned start_line; 272*38fd1498Szrj 273*38fd1498Szrj /* First line column. */ 274*38fd1498Szrj unsigned start_column; 275*38fd1498Szrj 276*38fd1498Szrj /* Last line number. */ 277*38fd1498Szrj unsigned end_line; 278*38fd1498Szrj 279*38fd1498Szrj /* Index of source file where the function is defined. */ 280*38fd1498Szrj unsigned src; 281*38fd1498Szrj 282*38fd1498Szrj /* Vector of line information. */ 283*38fd1498Szrj vector<line_info> lines; 284*38fd1498Szrj 285*38fd1498Szrj /* Next function. */ 286*38fd1498Szrj struct function_info *next; 287*38fd1498Szrj }; 288*38fd1498Szrj 289*38fd1498Szrj /* Function info comparer that will sort functions according to starting 290*38fd1498Szrj line. */ 291*38fd1498Szrj 292*38fd1498Szrj struct function_line_start_cmp 293*38fd1498Szrj { 294*38fd1498Szrj inline bool operator() (const function_info *lhs, 295*38fd1498Szrj const function_info *rhs) 296*38fd1498Szrj { 297*38fd1498Szrj return (lhs->start_line == rhs->start_line 298*38fd1498Szrj ? lhs->start_column < rhs->start_column 299*38fd1498Szrj : lhs->start_line < rhs->start_line); 300*38fd1498Szrj } 301*38fd1498Szrj }; 302*38fd1498Szrj 303*38fd1498Szrj /* Describes coverage of a file or function. */ 304*38fd1498Szrj 305*38fd1498Szrj struct coverage_info 306*38fd1498Szrj { 307*38fd1498Szrj int lines; 308*38fd1498Szrj int lines_executed; 309*38fd1498Szrj 310*38fd1498Szrj int branches; 311*38fd1498Szrj int branches_executed; 312*38fd1498Szrj int branches_taken; 313*38fd1498Szrj 314*38fd1498Szrj int calls; 315*38fd1498Szrj int calls_executed; 316*38fd1498Szrj 317*38fd1498Szrj char *name; 318*38fd1498Szrj }; 319*38fd1498Szrj 320*38fd1498Szrj /* Describes a file mentioned in the block graph. Contains an array 321*38fd1498Szrj of line info. */ 322*38fd1498Szrj 323*38fd1498Szrj struct source_info 324*38fd1498Szrj { 325*38fd1498Szrj /* Default constructor. */ 326*38fd1498Szrj source_info (); 327*38fd1498Szrj 328*38fd1498Szrj vector<function_info *> get_functions_at_location (unsigned line_num) const; 329*38fd1498Szrj 330*38fd1498Szrj /* Index of the source_info in sources vector. */ 331*38fd1498Szrj unsigned index; 332*38fd1498Szrj 333*38fd1498Szrj /* Canonical name of source file. */ 334*38fd1498Szrj char *name; 335*38fd1498Szrj time_t file_time; 336*38fd1498Szrj 337*38fd1498Szrj /* Vector of line information. */ 338*38fd1498Szrj vector<line_info> lines; 339*38fd1498Szrj 340*38fd1498Szrj coverage_info coverage; 341*38fd1498Szrj 342*38fd1498Szrj /* Functions in this source file. These are in ascending line 343*38fd1498Szrj number order. */ 344*38fd1498Szrj vector <function_info *> functions; 345*38fd1498Szrj }; 346*38fd1498Szrj 347*38fd1498Szrj source_info::source_info (): index (0), name (NULL), file_time (), 348*38fd1498Szrj lines (), coverage (), functions () 349*38fd1498Szrj { 350*38fd1498Szrj } 351*38fd1498Szrj 352*38fd1498Szrj vector<function_info *> 353*38fd1498Szrj source_info::get_functions_at_location (unsigned line_num) const 354*38fd1498Szrj { 355*38fd1498Szrj vector<function_info *> r; 356*38fd1498Szrj 357*38fd1498Szrj for (vector<function_info *>::const_iterator it = functions.begin (); 358*38fd1498Szrj it != functions.end (); it++) 359*38fd1498Szrj { 360*38fd1498Szrj if ((*it)->start_line == line_num && (*it)->src == index) 361*38fd1498Szrj r.push_back (*it); 362*38fd1498Szrj } 363*38fd1498Szrj 364*38fd1498Szrj std::sort (r.begin (), r.end (), function_line_start_cmp ()); 365*38fd1498Szrj 366*38fd1498Szrj return r; 367*38fd1498Szrj } 368*38fd1498Szrj 369*38fd1498Szrj class name_map 370*38fd1498Szrj { 371*38fd1498Szrj public: 372*38fd1498Szrj name_map () 373*38fd1498Szrj { 374*38fd1498Szrj } 375*38fd1498Szrj 376*38fd1498Szrj name_map (char *_name, unsigned _src): name (_name), src (_src) 377*38fd1498Szrj { 378*38fd1498Szrj } 379*38fd1498Szrj 380*38fd1498Szrj bool operator== (const name_map &rhs) const 381*38fd1498Szrj { 382*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 383*38fd1498Szrj return strcasecmp (this->name, rhs.name) == 0; 384*38fd1498Szrj #else 385*38fd1498Szrj return strcmp (this->name, rhs.name) == 0; 386*38fd1498Szrj #endif 387*38fd1498Szrj } 388*38fd1498Szrj 389*38fd1498Szrj bool operator< (const name_map &rhs) const 390*38fd1498Szrj { 391*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 392*38fd1498Szrj return strcasecmp (this->name, rhs.name) < 0; 393*38fd1498Szrj #else 394*38fd1498Szrj return strcmp (this->name, rhs.name) < 0; 395*38fd1498Szrj #endif 396*38fd1498Szrj } 397*38fd1498Szrj 398*38fd1498Szrj const char *name; /* Source file name */ 399*38fd1498Szrj unsigned src; /* Source file */ 400*38fd1498Szrj }; 401*38fd1498Szrj 402*38fd1498Szrj /* Vector of all functions. */ 403*38fd1498Szrj static vector<function_info *> functions; 404*38fd1498Szrj 405*38fd1498Szrj /* Vector of source files. */ 406*38fd1498Szrj static vector<source_info> sources; 407*38fd1498Szrj 408*38fd1498Szrj /* Mapping of file names to sources */ 409*38fd1498Szrj static vector<name_map> names; 410*38fd1498Szrj 411*38fd1498Szrj /* This holds data summary information. */ 412*38fd1498Szrj 413*38fd1498Szrj static unsigned object_runs; 414*38fd1498Szrj static unsigned program_count; 415*38fd1498Szrj 416*38fd1498Szrj static unsigned total_lines; 417*38fd1498Szrj static unsigned total_executed; 418*38fd1498Szrj 419*38fd1498Szrj /* Modification time of graph file. */ 420*38fd1498Szrj 421*38fd1498Szrj static time_t bbg_file_time; 422*38fd1498Szrj 423*38fd1498Szrj /* Name of the notes (gcno) output file. The "bbg" prefix is for 424*38fd1498Szrj historical reasons, when the notes file contained only the 425*38fd1498Szrj basic block graph notes. */ 426*38fd1498Szrj 427*38fd1498Szrj static char *bbg_file_name; 428*38fd1498Szrj 429*38fd1498Szrj /* Stamp of the bbg file */ 430*38fd1498Szrj static unsigned bbg_stamp; 431*38fd1498Szrj 432*38fd1498Szrj /* Supports has_unexecuted_blocks functionality. */ 433*38fd1498Szrj static unsigned bbg_supports_has_unexecuted_blocks; 434*38fd1498Szrj 435*38fd1498Szrj /* Name and file pointer of the input file for the count data (gcda). */ 436*38fd1498Szrj 437*38fd1498Szrj static char *da_file_name; 438*38fd1498Szrj 439*38fd1498Szrj /* Data file is missing. */ 440*38fd1498Szrj 441*38fd1498Szrj static int no_data_file; 442*38fd1498Szrj 443*38fd1498Szrj /* If there is several input files, compute and display results after 444*38fd1498Szrj reading all data files. This way if two or more gcda file refer to 445*38fd1498Szrj the same source file (eg inline subprograms in a .h file), the 446*38fd1498Szrj counts are added. */ 447*38fd1498Szrj 448*38fd1498Szrj static int multiple_files = 0; 449*38fd1498Szrj 450*38fd1498Szrj /* Output branch probabilities. */ 451*38fd1498Szrj 452*38fd1498Szrj static int flag_branches = 0; 453*38fd1498Szrj 454*38fd1498Szrj /* Show unconditional branches too. */ 455*38fd1498Szrj static int flag_unconditional = 0; 456*38fd1498Szrj 457*38fd1498Szrj /* Output a gcov file if this is true. This is on by default, and can 458*38fd1498Szrj be turned off by the -n option. */ 459*38fd1498Szrj 460*38fd1498Szrj static int flag_gcov_file = 1; 461*38fd1498Szrj 462*38fd1498Szrj /* Output progress indication if this is true. This is off by default 463*38fd1498Szrj and can be turned on by the -d option. */ 464*38fd1498Szrj 465*38fd1498Szrj static int flag_display_progress = 0; 466*38fd1498Szrj 467*38fd1498Szrj /* Output *.gcov file in intermediate format used by 'lcov'. */ 468*38fd1498Szrj 469*38fd1498Szrj static int flag_intermediate_format = 0; 470*38fd1498Szrj 471*38fd1498Szrj /* Output demangled function names. */ 472*38fd1498Szrj 473*38fd1498Szrj static int flag_demangled_names = 0; 474*38fd1498Szrj 475*38fd1498Szrj /* For included files, make the gcov output file name include the name 476*38fd1498Szrj of the input source file. For example, if x.h is included in a.c, 477*38fd1498Szrj then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ 478*38fd1498Szrj 479*38fd1498Szrj static int flag_long_names = 0; 480*38fd1498Szrj 481*38fd1498Szrj /* For situations when a long name can potentially hit filesystem path limit, 482*38fd1498Szrj let's calculate md5sum of the path and append it to a file name. */ 483*38fd1498Szrj 484*38fd1498Szrj static int flag_hash_filenames = 0; 485*38fd1498Szrj 486*38fd1498Szrj /* Print verbose informations. */ 487*38fd1498Szrj 488*38fd1498Szrj static int flag_verbose = 0; 489*38fd1498Szrj 490*38fd1498Szrj /* Print colored output. */ 491*38fd1498Szrj 492*38fd1498Szrj static int flag_use_colors = 0; 493*38fd1498Szrj 494*38fd1498Szrj /* Output count information for every basic block, not merely those 495*38fd1498Szrj that contain line number information. */ 496*38fd1498Szrj 497*38fd1498Szrj static int flag_all_blocks = 0; 498*38fd1498Szrj 499*38fd1498Szrj /* Output human readable numbers. */ 500*38fd1498Szrj 501*38fd1498Szrj static int flag_human_readable_numbers = 0; 502*38fd1498Szrj 503*38fd1498Szrj /* Output summary info for each function. */ 504*38fd1498Szrj 505*38fd1498Szrj static int flag_function_summary = 0; 506*38fd1498Szrj 507*38fd1498Szrj /* Object directory file prefix. This is the directory/file where the 508*38fd1498Szrj graph and data files are looked for, if nonzero. */ 509*38fd1498Szrj 510*38fd1498Szrj static char *object_directory = 0; 511*38fd1498Szrj 512*38fd1498Szrj /* Source directory prefix. This is removed from source pathnames 513*38fd1498Szrj that match, when generating the output file name. */ 514*38fd1498Szrj 515*38fd1498Szrj static char *source_prefix = 0; 516*38fd1498Szrj static size_t source_length = 0; 517*38fd1498Szrj 518*38fd1498Szrj /* Only show data for sources with relative pathnames. Absolute ones 519*38fd1498Szrj usually indicate a system header file, which although it may 520*38fd1498Szrj contain inline functions, is usually uninteresting. */ 521*38fd1498Szrj static int flag_relative_only = 0; 522*38fd1498Szrj 523*38fd1498Szrj /* Preserve all pathname components. Needed when object files and 524*38fd1498Szrj source files are in subdirectories. '/' is mangled as '#', '.' is 525*38fd1498Szrj elided and '..' mangled to '^'. */ 526*38fd1498Szrj 527*38fd1498Szrj static int flag_preserve_paths = 0; 528*38fd1498Szrj 529*38fd1498Szrj /* Output the number of times a branch was taken as opposed to the percentage 530*38fd1498Szrj of times it was taken. */ 531*38fd1498Szrj 532*38fd1498Szrj static int flag_counts = 0; 533*38fd1498Szrj 534*38fd1498Szrj /* Forward declarations. */ 535*38fd1498Szrj static int process_args (int, char **); 536*38fd1498Szrj static void print_usage (int) ATTRIBUTE_NORETURN; 537*38fd1498Szrj static void print_version (void) ATTRIBUTE_NORETURN; 538*38fd1498Szrj static void process_file (const char *); 539*38fd1498Szrj static void generate_results (const char *); 540*38fd1498Szrj static void create_file_names (const char *); 541*38fd1498Szrj static char *canonicalize_name (const char *); 542*38fd1498Szrj static unsigned find_source (const char *); 543*38fd1498Szrj static void read_graph_file (void); 544*38fd1498Szrj static int read_count_file (void); 545*38fd1498Szrj static void solve_flow_graph (function_info *); 546*38fd1498Szrj static void find_exception_blocks (function_info *); 547*38fd1498Szrj static void add_branch_counts (coverage_info *, const arc_info *); 548*38fd1498Szrj static void add_line_counts (coverage_info *, function_info *); 549*38fd1498Szrj static void executed_summary (unsigned, unsigned); 550*38fd1498Szrj static void function_summary (const coverage_info *, const char *); 551*38fd1498Szrj static const char *format_gcov (gcov_type, gcov_type, int); 552*38fd1498Szrj static void accumulate_line_counts (source_info *); 553*38fd1498Szrj static void output_gcov_file (const char *, source_info *); 554*38fd1498Szrj static int output_branch_count (FILE *, int, const arc_info *); 555*38fd1498Szrj static void output_lines (FILE *, const source_info *); 556*38fd1498Szrj static char *make_gcov_file_name (const char *, const char *); 557*38fd1498Szrj static char *mangle_name (const char *, char *); 558*38fd1498Szrj static void release_structures (void); 559*38fd1498Szrj extern int main (int, char **); 560*38fd1498Szrj 561*38fd1498Szrj function_info::function_info (): name (NULL), demangled_name (NULL), 562*38fd1498Szrj ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0), 563*38fd1498Szrj artificial (0), is_group (0), 564*38fd1498Szrj blocks (), blocks_executed (0), counts (), 565*38fd1498Szrj start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL) 566*38fd1498Szrj { 567*38fd1498Szrj } 568*38fd1498Szrj 569*38fd1498Szrj function_info::~function_info () 570*38fd1498Szrj { 571*38fd1498Szrj for (int i = blocks.size () - 1; i >= 0; i--) 572*38fd1498Szrj { 573*38fd1498Szrj arc_info *arc, *arc_n; 574*38fd1498Szrj 575*38fd1498Szrj for (arc = blocks[i].succ; arc; arc = arc_n) 576*38fd1498Szrj { 577*38fd1498Szrj arc_n = arc->succ_next; 578*38fd1498Szrj free (arc); 579*38fd1498Szrj } 580*38fd1498Szrj } 581*38fd1498Szrj if (flag_demangled_names && demangled_name != name) 582*38fd1498Szrj free (demangled_name); 583*38fd1498Szrj free (name); 584*38fd1498Szrj } 585*38fd1498Szrj 586*38fd1498Szrj bool function_info::group_line_p (unsigned n, unsigned src_idx) 587*38fd1498Szrj { 588*38fd1498Szrj return is_group && src == src_idx && start_line <= n && n <= end_line; 589*38fd1498Szrj } 590*38fd1498Szrj 591*38fd1498Szrj /* Cycle detection! 592*38fd1498Szrj There are a bajillion algorithms that do this. Boost's function is named 593*38fd1498Szrj hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in 594*38fd1498Szrj "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs" 595*38fd1498Szrj (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>). 596*38fd1498Szrj 597*38fd1498Szrj The basic algorithm is simple: effectively, we're finding all simple paths 598*38fd1498Szrj in a subgraph (that shrinks every iteration). Duplicates are filtered by 599*38fd1498Szrj "blocking" a path when a node is added to the path (this also prevents non- 600*38fd1498Szrj simple paths)--the node is unblocked only when it participates in a cycle. 601*38fd1498Szrj */ 602*38fd1498Szrj 603*38fd1498Szrj typedef vector<arc_info *> arc_vector_t; 604*38fd1498Szrj typedef vector<const block_info *> block_vector_t; 605*38fd1498Szrj 606*38fd1498Szrj /* Enum with types of loop in CFG. */ 607*38fd1498Szrj 608*38fd1498Szrj enum loop_type 609*38fd1498Szrj { 610*38fd1498Szrj NO_LOOP = 0, 611*38fd1498Szrj LOOP = 1, 612*38fd1498Szrj NEGATIVE_LOOP = 3 613*38fd1498Szrj }; 614*38fd1498Szrj 615*38fd1498Szrj /* Loop_type operator that merges two values: A and B. */ 616*38fd1498Szrj 617*38fd1498Szrj inline loop_type& operator |= (loop_type& a, loop_type b) 618*38fd1498Szrj { 619*38fd1498Szrj return a = static_cast<loop_type> (a | b); 620*38fd1498Szrj } 621*38fd1498Szrj 622*38fd1498Szrj /* Handle cycle identified by EDGES, where the function finds minimum cs_count 623*38fd1498Szrj and subtract the value from all counts. The subtracted value is added 624*38fd1498Szrj to COUNT. Returns type of loop. */ 625*38fd1498Szrj 626*38fd1498Szrj static loop_type 627*38fd1498Szrj handle_cycle (const arc_vector_t &edges, int64_t &count) 628*38fd1498Szrj { 629*38fd1498Szrj /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by 630*38fd1498Szrj that amount. */ 631*38fd1498Szrj int64_t cycle_count = INTTYPE_MAXIMUM (int64_t); 632*38fd1498Szrj for (unsigned i = 0; i < edges.size (); i++) 633*38fd1498Szrj { 634*38fd1498Szrj int64_t ecount = edges[i]->cs_count; 635*38fd1498Szrj if (cycle_count > ecount) 636*38fd1498Szrj cycle_count = ecount; 637*38fd1498Szrj } 638*38fd1498Szrj count += cycle_count; 639*38fd1498Szrj for (unsigned i = 0; i < edges.size (); i++) 640*38fd1498Szrj edges[i]->cs_count -= cycle_count; 641*38fd1498Szrj 642*38fd1498Szrj return cycle_count < 0 ? NEGATIVE_LOOP : LOOP; 643*38fd1498Szrj } 644*38fd1498Szrj 645*38fd1498Szrj /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks 646*38fd1498Szrj blocked by U in BLOCK_LISTS. */ 647*38fd1498Szrj 648*38fd1498Szrj static void 649*38fd1498Szrj unblock (const block_info *u, block_vector_t &blocked, 650*38fd1498Szrj vector<block_vector_t > &block_lists) 651*38fd1498Szrj { 652*38fd1498Szrj block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u); 653*38fd1498Szrj if (it == blocked.end ()) 654*38fd1498Szrj return; 655*38fd1498Szrj 656*38fd1498Szrj unsigned index = it - blocked.begin (); 657*38fd1498Szrj blocked.erase (it); 658*38fd1498Szrj 659*38fd1498Szrj block_vector_t to_unblock (block_lists[index]); 660*38fd1498Szrj 661*38fd1498Szrj block_lists.erase (block_lists.begin () + index); 662*38fd1498Szrj 663*38fd1498Szrj for (block_vector_t::iterator it = to_unblock.begin (); 664*38fd1498Szrj it != to_unblock.end (); it++) 665*38fd1498Szrj unblock (*it, blocked, block_lists); 666*38fd1498Szrj } 667*38fd1498Szrj 668*38fd1498Szrj /* Find circuit going to block V, PATH is provisional seen cycle. 669*38fd1498Szrj BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices 670*38fd1498Szrj blocked by a block. COUNT is accumulated count of the current LINE. 671*38fd1498Szrj Returns what type of loop it contains. */ 672*38fd1498Szrj 673*38fd1498Szrj static loop_type 674*38fd1498Szrj circuit (block_info *v, arc_vector_t &path, block_info *start, 675*38fd1498Szrj block_vector_t &blocked, vector<block_vector_t> &block_lists, 676*38fd1498Szrj line_info &linfo, int64_t &count) 677*38fd1498Szrj { 678*38fd1498Szrj loop_type result = NO_LOOP; 679*38fd1498Szrj 680*38fd1498Szrj /* Add v to the block list. */ 681*38fd1498Szrj gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ()); 682*38fd1498Szrj blocked.push_back (v); 683*38fd1498Szrj block_lists.push_back (block_vector_t ()); 684*38fd1498Szrj 685*38fd1498Szrj for (arc_info *arc = v->succ; arc; arc = arc->succ_next) 686*38fd1498Szrj { 687*38fd1498Szrj block_info *w = arc->dst; 688*38fd1498Szrj if (w < start || !linfo.has_block (w)) 689*38fd1498Szrj continue; 690*38fd1498Szrj 691*38fd1498Szrj path.push_back (arc); 692*38fd1498Szrj if (w == start) 693*38fd1498Szrj /* Cycle has been found. */ 694*38fd1498Szrj result |= handle_cycle (path, count); 695*38fd1498Szrj else if (find (blocked.begin (), blocked.end (), w) == blocked.end ()) 696*38fd1498Szrj result |= circuit (w, path, start, blocked, block_lists, linfo, count); 697*38fd1498Szrj 698*38fd1498Szrj path.pop_back (); 699*38fd1498Szrj } 700*38fd1498Szrj 701*38fd1498Szrj if (result != NO_LOOP) 702*38fd1498Szrj unblock (v, blocked, block_lists); 703*38fd1498Szrj else 704*38fd1498Szrj for (arc_info *arc = v->succ; arc; arc = arc->succ_next) 705*38fd1498Szrj { 706*38fd1498Szrj block_info *w = arc->dst; 707*38fd1498Szrj if (w < start || !linfo.has_block (w)) 708*38fd1498Szrj continue; 709*38fd1498Szrj 710*38fd1498Szrj size_t index 711*38fd1498Szrj = find (blocked.begin (), blocked.end (), w) - blocked.begin (); 712*38fd1498Szrj gcc_assert (index < blocked.size ()); 713*38fd1498Szrj block_vector_t &list = block_lists[index]; 714*38fd1498Szrj if (find (list.begin (), list.end (), v) == list.end ()) 715*38fd1498Szrj list.push_back (v); 716*38fd1498Szrj } 717*38fd1498Szrj 718*38fd1498Szrj return result; 719*38fd1498Szrj } 720*38fd1498Szrj 721*38fd1498Szrj /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line 722*38fd1498Szrj contains a negative loop, then perform the same function once again. */ 723*38fd1498Szrj 724*38fd1498Szrj static gcov_type 725*38fd1498Szrj get_cycles_count (line_info &linfo, bool handle_negative_cycles = true) 726*38fd1498Szrj { 727*38fd1498Szrj /* Note that this algorithm works even if blocks aren't in sorted order. 728*38fd1498Szrj Each iteration of the circuit detection is completely independent 729*38fd1498Szrj (except for reducing counts, but that shouldn't matter anyways). 730*38fd1498Szrj Therefore, operating on a permuted order (i.e., non-sorted) only 731*38fd1498Szrj has the effect of permuting the output cycles. */ 732*38fd1498Szrj 733*38fd1498Szrj loop_type result = NO_LOOP; 734*38fd1498Szrj gcov_type count = 0; 735*38fd1498Szrj for (vector<block_info *>::iterator it = linfo.blocks.begin (); 736*38fd1498Szrj it != linfo.blocks.end (); it++) 737*38fd1498Szrj { 738*38fd1498Szrj arc_vector_t path; 739*38fd1498Szrj block_vector_t blocked; 740*38fd1498Szrj vector<block_vector_t > block_lists; 741*38fd1498Szrj result |= circuit (*it, path, *it, blocked, block_lists, linfo, 742*38fd1498Szrj count); 743*38fd1498Szrj } 744*38fd1498Szrj 745*38fd1498Szrj /* If we have a negative cycle, repeat the find_cycles routine. */ 746*38fd1498Szrj if (result == NEGATIVE_LOOP && handle_negative_cycles) 747*38fd1498Szrj count += get_cycles_count (linfo, false); 748*38fd1498Szrj 749*38fd1498Szrj return count; 750*38fd1498Szrj } 751*38fd1498Szrj 752*38fd1498Szrj int 753*38fd1498Szrj main (int argc, char **argv) 754*38fd1498Szrj { 755*38fd1498Szrj int argno; 756*38fd1498Szrj int first_arg; 757*38fd1498Szrj const char *p; 758*38fd1498Szrj 759*38fd1498Szrj p = argv[0] + strlen (argv[0]); 760*38fd1498Szrj while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) 761*38fd1498Szrj --p; 762*38fd1498Szrj progname = p; 763*38fd1498Szrj 764*38fd1498Szrj xmalloc_set_program_name (progname); 765*38fd1498Szrj 766*38fd1498Szrj /* Unlock the stdio streams. */ 767*38fd1498Szrj unlock_std_streams (); 768*38fd1498Szrj 769*38fd1498Szrj gcc_init_libintl (); 770*38fd1498Szrj 771*38fd1498Szrj diagnostic_initialize (global_dc, 0); 772*38fd1498Szrj 773*38fd1498Szrj /* Handle response files. */ 774*38fd1498Szrj expandargv (&argc, &argv); 775*38fd1498Szrj 776*38fd1498Szrj argno = process_args (argc, argv); 777*38fd1498Szrj if (optind == argc) 778*38fd1498Szrj print_usage (true); 779*38fd1498Szrj 780*38fd1498Szrj if (argc - argno > 1) 781*38fd1498Szrj multiple_files = 1; 782*38fd1498Szrj 783*38fd1498Szrj first_arg = argno; 784*38fd1498Szrj 785*38fd1498Szrj for (; argno != argc; argno++) 786*38fd1498Szrj { 787*38fd1498Szrj if (flag_display_progress) 788*38fd1498Szrj printf ("Processing file %d out of %d\n", argno - first_arg + 1, 789*38fd1498Szrj argc - first_arg); 790*38fd1498Szrj process_file (argv[argno]); 791*38fd1498Szrj 792*38fd1498Szrj if (flag_intermediate_format || argno == argc - 1) 793*38fd1498Szrj { 794*38fd1498Szrj generate_results (argv[argno]); 795*38fd1498Szrj release_structures (); 796*38fd1498Szrj } 797*38fd1498Szrj } 798*38fd1498Szrj 799*38fd1498Szrj return 0; 800*38fd1498Szrj } 801*38fd1498Szrj 802*38fd1498Szrj /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, 803*38fd1498Szrj otherwise the output of --help. */ 804*38fd1498Szrj 805*38fd1498Szrj static void 806*38fd1498Szrj print_usage (int error_p) 807*38fd1498Szrj { 808*38fd1498Szrj FILE *file = error_p ? stderr : stdout; 809*38fd1498Szrj int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 810*38fd1498Szrj 811*38fd1498Szrj fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n"); 812*38fd1498Szrj fnotice (file, "Print code coverage information.\n\n"); 813*38fd1498Szrj fnotice (file, " -a, --all-blocks Show information for every basic block\n"); 814*38fd1498Szrj fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n"); 815*38fd1498Szrj fnotice (file, " -c, --branch-counts Output counts of branches taken\n\ 816*38fd1498Szrj rather than percentages\n"); 817*38fd1498Szrj fnotice (file, " -d, --display-progress Display progress information\n"); 818*38fd1498Szrj fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 819*38fd1498Szrj fnotice (file, " -h, --help Print this help, then exit\n"); 820*38fd1498Szrj fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n"); 821*38fd1498Szrj fnotice (file, " -j, --human-readable Output human readable numbers\n"); 822*38fd1498Szrj fnotice (file, " -k, --use-colors Emit colored output\n"); 823*38fd1498Szrj fnotice (file, " -l, --long-file-names Use long output file names for included\n\ 824*38fd1498Szrj source files\n"); 825*38fd1498Szrj fnotice (file, " -m, --demangled-names Output demangled function names\n"); 826*38fd1498Szrj fnotice (file, " -n, --no-output Do not create an output file\n"); 827*38fd1498Szrj fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); 828*38fd1498Szrj fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); 829*38fd1498Szrj fnotice (file, " -r, --relative-only Only show data for relative sources\n"); 830*38fd1498Szrj fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n"); 831*38fd1498Szrj fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); 832*38fd1498Szrj fnotice (file, " -v, --version Print version number, then exit\n"); 833*38fd1498Szrj fnotice (file, " -w, --verbose Print verbose informations\n"); 834*38fd1498Szrj fnotice (file, " -x, --hash-filenames Hash long pathnames\n"); 835*38fd1498Szrj fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", 836*38fd1498Szrj bug_report_url); 837*38fd1498Szrj exit (status); 838*38fd1498Szrj } 839*38fd1498Szrj 840*38fd1498Szrj /* Print version information and exit. */ 841*38fd1498Szrj 842*38fd1498Szrj static void 843*38fd1498Szrj print_version (void) 844*38fd1498Szrj { 845*38fd1498Szrj fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string); 846*38fd1498Szrj fprintf (stdout, "Copyright %s 2018 Free Software Foundation, Inc.\n", 847*38fd1498Szrj _("(C)")); 848*38fd1498Szrj fnotice (stdout, 849*38fd1498Szrj _("This is free software; see the source for copying conditions.\n" 850*38fd1498Szrj "There is NO warranty; not even for MERCHANTABILITY or \n" 851*38fd1498Szrj "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 852*38fd1498Szrj exit (SUCCESS_EXIT_CODE); 853*38fd1498Szrj } 854*38fd1498Szrj 855*38fd1498Szrj static const struct option options[] = 856*38fd1498Szrj { 857*38fd1498Szrj { "help", no_argument, NULL, 'h' }, 858*38fd1498Szrj { "version", no_argument, NULL, 'v' }, 859*38fd1498Szrj { "verbose", no_argument, NULL, 'w' }, 860*38fd1498Szrj { "all-blocks", no_argument, NULL, 'a' }, 861*38fd1498Szrj { "branch-probabilities", no_argument, NULL, 'b' }, 862*38fd1498Szrj { "branch-counts", no_argument, NULL, 'c' }, 863*38fd1498Szrj { "intermediate-format", no_argument, NULL, 'i' }, 864*38fd1498Szrj { "human-readable", no_argument, NULL, 'j' }, 865*38fd1498Szrj { "no-output", no_argument, NULL, 'n' }, 866*38fd1498Szrj { "long-file-names", no_argument, NULL, 'l' }, 867*38fd1498Szrj { "function-summaries", no_argument, NULL, 'f' }, 868*38fd1498Szrj { "demangled-names", no_argument, NULL, 'm' }, 869*38fd1498Szrj { "preserve-paths", no_argument, NULL, 'p' }, 870*38fd1498Szrj { "relative-only", no_argument, NULL, 'r' }, 871*38fd1498Szrj { "object-directory", required_argument, NULL, 'o' }, 872*38fd1498Szrj { "object-file", required_argument, NULL, 'o' }, 873*38fd1498Szrj { "source-prefix", required_argument, NULL, 's' }, 874*38fd1498Szrj { "unconditional-branches", no_argument, NULL, 'u' }, 875*38fd1498Szrj { "display-progress", no_argument, NULL, 'd' }, 876*38fd1498Szrj { "hash-filenames", no_argument, NULL, 'x' }, 877*38fd1498Szrj { "use-colors", no_argument, NULL, 'k' }, 878*38fd1498Szrj { 0, 0, 0, 0 } 879*38fd1498Szrj }; 880*38fd1498Szrj 881*38fd1498Szrj /* Process args, return index to first non-arg. */ 882*38fd1498Szrj 883*38fd1498Szrj static int 884*38fd1498Szrj process_args (int argc, char **argv) 885*38fd1498Szrj { 886*38fd1498Szrj int opt; 887*38fd1498Szrj 888*38fd1498Szrj const char *opts = "abcdfhijklmno:prs:uvwx"; 889*38fd1498Szrj while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1) 890*38fd1498Szrj { 891*38fd1498Szrj switch (opt) 892*38fd1498Szrj { 893*38fd1498Szrj case 'a': 894*38fd1498Szrj flag_all_blocks = 1; 895*38fd1498Szrj break; 896*38fd1498Szrj case 'b': 897*38fd1498Szrj flag_branches = 1; 898*38fd1498Szrj break; 899*38fd1498Szrj case 'c': 900*38fd1498Szrj flag_counts = 1; 901*38fd1498Szrj break; 902*38fd1498Szrj case 'f': 903*38fd1498Szrj flag_function_summary = 1; 904*38fd1498Szrj break; 905*38fd1498Szrj case 'h': 906*38fd1498Szrj print_usage (false); 907*38fd1498Szrj /* print_usage will exit. */ 908*38fd1498Szrj case 'l': 909*38fd1498Szrj flag_long_names = 1; 910*38fd1498Szrj break; 911*38fd1498Szrj case 'j': 912*38fd1498Szrj flag_human_readable_numbers = 1; 913*38fd1498Szrj break; 914*38fd1498Szrj case 'k': 915*38fd1498Szrj flag_use_colors = 1; 916*38fd1498Szrj break; 917*38fd1498Szrj case 'm': 918*38fd1498Szrj flag_demangled_names = 1; 919*38fd1498Szrj break; 920*38fd1498Szrj case 'n': 921*38fd1498Szrj flag_gcov_file = 0; 922*38fd1498Szrj break; 923*38fd1498Szrj case 'o': 924*38fd1498Szrj object_directory = optarg; 925*38fd1498Szrj break; 926*38fd1498Szrj case 's': 927*38fd1498Szrj source_prefix = optarg; 928*38fd1498Szrj source_length = strlen (source_prefix); 929*38fd1498Szrj break; 930*38fd1498Szrj case 'r': 931*38fd1498Szrj flag_relative_only = 1; 932*38fd1498Szrj break; 933*38fd1498Szrj case 'p': 934*38fd1498Szrj flag_preserve_paths = 1; 935*38fd1498Szrj break; 936*38fd1498Szrj case 'u': 937*38fd1498Szrj flag_unconditional = 1; 938*38fd1498Szrj break; 939*38fd1498Szrj case 'i': 940*38fd1498Szrj flag_intermediate_format = 1; 941*38fd1498Szrj flag_gcov_file = 1; 942*38fd1498Szrj break; 943*38fd1498Szrj case 'd': 944*38fd1498Szrj flag_display_progress = 1; 945*38fd1498Szrj break; 946*38fd1498Szrj case 'x': 947*38fd1498Szrj flag_hash_filenames = 1; 948*38fd1498Szrj break; 949*38fd1498Szrj case 'w': 950*38fd1498Szrj flag_verbose = 1; 951*38fd1498Szrj break; 952*38fd1498Szrj case 'v': 953*38fd1498Szrj print_version (); 954*38fd1498Szrj /* print_version will exit. */ 955*38fd1498Szrj default: 956*38fd1498Szrj print_usage (true); 957*38fd1498Szrj /* print_usage will exit. */ 958*38fd1498Szrj } 959*38fd1498Szrj } 960*38fd1498Szrj 961*38fd1498Szrj return optind; 962*38fd1498Szrj } 963*38fd1498Szrj 964*38fd1498Szrj /* Output intermediate LINE sitting on LINE_NUM to output file F. */ 965*38fd1498Szrj 966*38fd1498Szrj static void 967*38fd1498Szrj output_intermediate_line (FILE *f, line_info *line, unsigned line_num) 968*38fd1498Szrj { 969*38fd1498Szrj if (!line->exists) 970*38fd1498Szrj return; 971*38fd1498Szrj 972*38fd1498Szrj fprintf (f, "lcount:%u,%s,%d\n", line_num, 973*38fd1498Szrj format_gcov (line->count, 0, -1), 974*38fd1498Szrj line->has_unexecuted_block); 975*38fd1498Szrj 976*38fd1498Szrj vector<arc_info *>::const_iterator it; 977*38fd1498Szrj if (flag_branches) 978*38fd1498Szrj for (it = line->branches.begin (); it != line->branches.end (); 979*38fd1498Szrj it++) 980*38fd1498Szrj { 981*38fd1498Szrj if (!(*it)->is_unconditional && !(*it)->is_call_non_return) 982*38fd1498Szrj { 983*38fd1498Szrj const char *branch_type; 984*38fd1498Szrj /* branch:<line_num>,<branch_coverage_infoype> 985*38fd1498Szrj branch_coverage_infoype 986*38fd1498Szrj : notexec (Branch not executed) 987*38fd1498Szrj : taken (Branch executed and taken) 988*38fd1498Szrj : nottaken (Branch executed, but not taken) 989*38fd1498Szrj */ 990*38fd1498Szrj if ((*it)->src->count) 991*38fd1498Szrj branch_type 992*38fd1498Szrj = ((*it)->count > 0) ? "taken" : "nottaken"; 993*38fd1498Szrj else 994*38fd1498Szrj branch_type = "notexec"; 995*38fd1498Szrj fprintf (f, "branch:%d,%s\n", line_num, branch_type); 996*38fd1498Szrj } 997*38fd1498Szrj } 998*38fd1498Szrj } 999*38fd1498Szrj 1000*38fd1498Szrj /* Get the name of the gcov file. The return value must be free'd. 1001*38fd1498Szrj 1002*38fd1498Szrj It appends the '.gcov' extension to the *basename* of the file. 1003*38fd1498Szrj The resulting file name will be in PWD. 1004*38fd1498Szrj 1005*38fd1498Szrj e.g., 1006*38fd1498Szrj input: foo.da, output: foo.da.gcov 1007*38fd1498Szrj input: a/b/foo.cc, output: foo.cc.gcov */ 1008*38fd1498Szrj 1009*38fd1498Szrj static char * 1010*38fd1498Szrj get_gcov_intermediate_filename (const char *file_name) 1011*38fd1498Szrj { 1012*38fd1498Szrj const char *gcov = ".gcov"; 1013*38fd1498Szrj char *result; 1014*38fd1498Szrj const char *cptr; 1015*38fd1498Szrj 1016*38fd1498Szrj /* Find the 'basename'. */ 1017*38fd1498Szrj cptr = lbasename (file_name); 1018*38fd1498Szrj 1019*38fd1498Szrj result = XNEWVEC (char, strlen (cptr) + strlen (gcov) + 1); 1020*38fd1498Szrj sprintf (result, "%s%s", cptr, gcov); 1021*38fd1498Szrj 1022*38fd1498Szrj return result; 1023*38fd1498Szrj } 1024*38fd1498Szrj 1025*38fd1498Szrj /* Output the result in intermediate format used by 'lcov'. 1026*38fd1498Szrj 1027*38fd1498Szrj The intermediate format contains a single file named 'foo.cc.gcov', 1028*38fd1498Szrj with no source code included. 1029*38fd1498Szrj 1030*38fd1498Szrj The default gcov outputs multiple files: 'foo.cc.gcov', 1031*38fd1498Szrj 'iostream.gcov', 'ios_base.h.gcov', etc. with source code 1032*38fd1498Szrj included. Instead the intermediate format here outputs only a single 1033*38fd1498Szrj file 'foo.cc.gcov' similar to the above example. */ 1034*38fd1498Szrj 1035*38fd1498Szrj static void 1036*38fd1498Szrj output_intermediate_file (FILE *gcov_file, source_info *src) 1037*38fd1498Szrj { 1038*38fd1498Szrj fprintf (gcov_file, "version:%s\n", version_string); 1039*38fd1498Szrj fprintf (gcov_file, "file:%s\n", src->name); /* source file name */ 1040*38fd1498Szrj 1041*38fd1498Szrj std::sort (src->functions.begin (), src->functions.end (), 1042*38fd1498Szrj function_line_start_cmp ()); 1043*38fd1498Szrj for (vector<function_info *>::iterator it = src->functions.begin (); 1044*38fd1498Szrj it != src->functions.end (); it++) 1045*38fd1498Szrj { 1046*38fd1498Szrj /* function:<name>,<line_number>,<execution_count> */ 1047*38fd1498Szrj fprintf (gcov_file, "function:%d,%d,%s,%s\n", (*it)->start_line, 1048*38fd1498Szrj (*it)->end_line, format_gcov ((*it)->blocks[0].count, 0, -1), 1049*38fd1498Szrj flag_demangled_names ? (*it)->demangled_name : (*it)->name); 1050*38fd1498Szrj } 1051*38fd1498Szrj 1052*38fd1498Szrj for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++) 1053*38fd1498Szrj { 1054*38fd1498Szrj vector<function_info *> fns = src->get_functions_at_location (line_num); 1055*38fd1498Szrj 1056*38fd1498Szrj /* Print first group functions that begin on the line. */ 1057*38fd1498Szrj for (vector<function_info *>::iterator it2 = fns.begin (); 1058*38fd1498Szrj it2 != fns.end (); it2++) 1059*38fd1498Szrj { 1060*38fd1498Szrj vector<line_info> &lines = (*it2)->lines; 1061*38fd1498Szrj for (unsigned i = 0; i < lines.size (); i++) 1062*38fd1498Szrj { 1063*38fd1498Szrj line_info *line = &lines[i]; 1064*38fd1498Szrj output_intermediate_line (gcov_file, line, line_num + i); 1065*38fd1498Szrj } 1066*38fd1498Szrj } 1067*38fd1498Szrj 1068*38fd1498Szrj /* Follow with lines associated with the source file. */ 1069*38fd1498Szrj output_intermediate_line (gcov_file, &src->lines[line_num], line_num); 1070*38fd1498Szrj } 1071*38fd1498Szrj } 1072*38fd1498Szrj 1073*38fd1498Szrj /* Function start pair. */ 1074*38fd1498Szrj struct function_start 1075*38fd1498Szrj { 1076*38fd1498Szrj unsigned source_file_idx; 1077*38fd1498Szrj unsigned start_line; 1078*38fd1498Szrj }; 1079*38fd1498Szrj 1080*38fd1498Szrj /* Traits class for function start hash maps below. */ 1081*38fd1498Szrj 1082*38fd1498Szrj struct function_start_pair_hash : typed_noop_remove <function_start> 1083*38fd1498Szrj { 1084*38fd1498Szrj typedef function_start value_type; 1085*38fd1498Szrj typedef function_start compare_type; 1086*38fd1498Szrj 1087*38fd1498Szrj static hashval_t 1088*38fd1498Szrj hash (const function_start &ref) 1089*38fd1498Szrj { 1090*38fd1498Szrj inchash::hash hstate (0); 1091*38fd1498Szrj hstate.add_int (ref.source_file_idx); 1092*38fd1498Szrj hstate.add_int (ref.start_line); 1093*38fd1498Szrj return hstate.end (); 1094*38fd1498Szrj } 1095*38fd1498Szrj 1096*38fd1498Szrj static bool 1097*38fd1498Szrj equal (const function_start &ref1, const function_start &ref2) 1098*38fd1498Szrj { 1099*38fd1498Szrj return (ref1.source_file_idx == ref2.source_file_idx 1100*38fd1498Szrj && ref1.start_line == ref2.start_line); 1101*38fd1498Szrj } 1102*38fd1498Szrj 1103*38fd1498Szrj static void 1104*38fd1498Szrj mark_deleted (function_start &ref) 1105*38fd1498Szrj { 1106*38fd1498Szrj ref.start_line = ~1U; 1107*38fd1498Szrj } 1108*38fd1498Szrj 1109*38fd1498Szrj static void 1110*38fd1498Szrj mark_empty (function_start &ref) 1111*38fd1498Szrj { 1112*38fd1498Szrj ref.start_line = ~2U; 1113*38fd1498Szrj } 1114*38fd1498Szrj 1115*38fd1498Szrj static bool 1116*38fd1498Szrj is_deleted (const function_start &ref) 1117*38fd1498Szrj { 1118*38fd1498Szrj return ref.start_line == ~1U; 1119*38fd1498Szrj } 1120*38fd1498Szrj 1121*38fd1498Szrj static bool 1122*38fd1498Szrj is_empty (const function_start &ref) 1123*38fd1498Szrj { 1124*38fd1498Szrj return ref.start_line == ~2U; 1125*38fd1498Szrj } 1126*38fd1498Szrj }; 1127*38fd1498Szrj 1128*38fd1498Szrj /* Process a single input file. */ 1129*38fd1498Szrj 1130*38fd1498Szrj static void 1131*38fd1498Szrj process_file (const char *file_name) 1132*38fd1498Szrj { 1133*38fd1498Szrj create_file_names (file_name); 1134*38fd1498Szrj read_graph_file (); 1135*38fd1498Szrj if (functions.empty ()) 1136*38fd1498Szrj return; 1137*38fd1498Szrj 1138*38fd1498Szrj read_count_file (); 1139*38fd1498Szrj 1140*38fd1498Szrj hash_map<function_start_pair_hash, function_info *> fn_map; 1141*38fd1498Szrj 1142*38fd1498Szrj /* Identify group functions. */ 1143*38fd1498Szrj for (vector<function_info *>::iterator it = functions.begin (); 1144*38fd1498Szrj it != functions.end (); it++) 1145*38fd1498Szrj if (!(*it)->artificial) 1146*38fd1498Szrj { 1147*38fd1498Szrj function_start needle; 1148*38fd1498Szrj needle.source_file_idx = (*it)->src; 1149*38fd1498Szrj needle.start_line = (*it)->start_line; 1150*38fd1498Szrj 1151*38fd1498Szrj function_info **slot = fn_map.get (needle); 1152*38fd1498Szrj if (slot) 1153*38fd1498Szrj { 1154*38fd1498Szrj (*slot)->is_group = 1; 1155*38fd1498Szrj (*it)->is_group = 1; 1156*38fd1498Szrj } 1157*38fd1498Szrj else 1158*38fd1498Szrj fn_map.put (needle, *it); 1159*38fd1498Szrj } 1160*38fd1498Szrj 1161*38fd1498Szrj /* Remove all artificial function. */ 1162*38fd1498Szrj functions.erase (remove_if (functions.begin (), functions.end (), 1163*38fd1498Szrj function_info::is_artificial), functions.end ()); 1164*38fd1498Szrj 1165*38fd1498Szrj for (vector<function_info *>::iterator it = functions.begin (); 1166*38fd1498Szrj it != functions.end (); it++) 1167*38fd1498Szrj { 1168*38fd1498Szrj function_info *fn = *it; 1169*38fd1498Szrj unsigned src = fn->src; 1170*38fd1498Szrj 1171*38fd1498Szrj if (!fn->counts.empty () || no_data_file) 1172*38fd1498Szrj { 1173*38fd1498Szrj source_info *s = &sources[src]; 1174*38fd1498Szrj s->functions.push_back (fn); 1175*38fd1498Szrj 1176*38fd1498Szrj /* Mark last line in files touched by function. */ 1177*38fd1498Szrj for (unsigned block_no = 0; block_no != fn->blocks.size (); 1178*38fd1498Szrj block_no++) 1179*38fd1498Szrj { 1180*38fd1498Szrj block_info *block = &fn->blocks[block_no]; 1181*38fd1498Szrj for (unsigned i = 0; i < block->locations.size (); i++) 1182*38fd1498Szrj { 1183*38fd1498Szrj /* Sort lines of locations. */ 1184*38fd1498Szrj sort (block->locations[i].lines.begin (), 1185*38fd1498Szrj block->locations[i].lines.end ()); 1186*38fd1498Szrj 1187*38fd1498Szrj if (!block->locations[i].lines.empty ()) 1188*38fd1498Szrj { 1189*38fd1498Szrj s = &sources[block->locations[i].source_file_idx]; 1190*38fd1498Szrj unsigned last_line 1191*38fd1498Szrj = block->locations[i].lines.back (); 1192*38fd1498Szrj 1193*38fd1498Szrj /* Record new lines for the function. */ 1194*38fd1498Szrj if (last_line >= s->lines.size ()) 1195*38fd1498Szrj { 1196*38fd1498Szrj s = &sources[block->locations[i].source_file_idx]; 1197*38fd1498Szrj unsigned last_line 1198*38fd1498Szrj = block->locations[i].lines.back (); 1199*38fd1498Szrj 1200*38fd1498Szrj /* Record new lines for the function. */ 1201*38fd1498Szrj if (last_line >= s->lines.size ()) 1202*38fd1498Szrj { 1203*38fd1498Szrj /* Record new lines for a source file. */ 1204*38fd1498Szrj s->lines.resize (last_line + 1); 1205*38fd1498Szrj } 1206*38fd1498Szrj } 1207*38fd1498Szrj } 1208*38fd1498Szrj } 1209*38fd1498Szrj } 1210*38fd1498Szrj 1211*38fd1498Szrj /* Allocate lines for group function, following start_line 1212*38fd1498Szrj and end_line information of the function. */ 1213*38fd1498Szrj if (fn->is_group) 1214*38fd1498Szrj fn->lines.resize (fn->end_line - fn->start_line + 1); 1215*38fd1498Szrj 1216*38fd1498Szrj 1217*38fd1498Szrj solve_flow_graph (fn); 1218*38fd1498Szrj if (fn->has_catch) 1219*38fd1498Szrj find_exception_blocks (fn); 1220*38fd1498Szrj } 1221*38fd1498Szrj else 1222*38fd1498Szrj { 1223*38fd1498Szrj /* The function was not in the executable -- some other 1224*38fd1498Szrj instance must have been selected. */ 1225*38fd1498Szrj } 1226*38fd1498Szrj } 1227*38fd1498Szrj } 1228*38fd1498Szrj 1229*38fd1498Szrj static void 1230*38fd1498Szrj output_gcov_file (const char *file_name, source_info *src) 1231*38fd1498Szrj { 1232*38fd1498Szrj char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name); 1233*38fd1498Szrj 1234*38fd1498Szrj if (src->coverage.lines) 1235*38fd1498Szrj { 1236*38fd1498Szrj FILE *gcov_file = fopen (gcov_file_name, "w"); 1237*38fd1498Szrj if (gcov_file) 1238*38fd1498Szrj { 1239*38fd1498Szrj fnotice (stdout, "Creating '%s'\n", gcov_file_name); 1240*38fd1498Szrj output_lines (gcov_file, src); 1241*38fd1498Szrj if (ferror (gcov_file)) 1242*38fd1498Szrj fnotice (stderr, "Error writing output file '%s'\n", 1243*38fd1498Szrj gcov_file_name); 1244*38fd1498Szrj fclose (gcov_file); 1245*38fd1498Szrj } 1246*38fd1498Szrj else 1247*38fd1498Szrj fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name); 1248*38fd1498Szrj } 1249*38fd1498Szrj else 1250*38fd1498Szrj { 1251*38fd1498Szrj unlink (gcov_file_name); 1252*38fd1498Szrj fnotice (stdout, "Removing '%s'\n", gcov_file_name); 1253*38fd1498Szrj } 1254*38fd1498Szrj free (gcov_file_name); 1255*38fd1498Szrj } 1256*38fd1498Szrj 1257*38fd1498Szrj static void 1258*38fd1498Szrj generate_results (const char *file_name) 1259*38fd1498Szrj { 1260*38fd1498Szrj FILE *gcov_intermediate_file = NULL; 1261*38fd1498Szrj char *gcov_intermediate_filename = NULL; 1262*38fd1498Szrj 1263*38fd1498Szrj for (vector<function_info *>::iterator it = functions.begin (); 1264*38fd1498Szrj it != functions.end (); it++) 1265*38fd1498Szrj { 1266*38fd1498Szrj function_info *fn = *it; 1267*38fd1498Szrj coverage_info coverage; 1268*38fd1498Szrj 1269*38fd1498Szrj memset (&coverage, 0, sizeof (coverage)); 1270*38fd1498Szrj coverage.name = flag_demangled_names ? fn->demangled_name : fn->name; 1271*38fd1498Szrj add_line_counts (flag_function_summary ? &coverage : NULL, fn); 1272*38fd1498Szrj if (flag_function_summary) 1273*38fd1498Szrj { 1274*38fd1498Szrj function_summary (&coverage, "Function"); 1275*38fd1498Szrj fnotice (stdout, "\n"); 1276*38fd1498Szrj } 1277*38fd1498Szrj } 1278*38fd1498Szrj 1279*38fd1498Szrj name_map needle; 1280*38fd1498Szrj 1281*38fd1498Szrj if (file_name) 1282*38fd1498Szrj { 1283*38fd1498Szrj needle.name = file_name; 1284*38fd1498Szrj vector<name_map>::iterator it = std::find (names.begin (), names.end (), 1285*38fd1498Szrj needle); 1286*38fd1498Szrj if (it != names.end ()) 1287*38fd1498Szrj file_name = sources[it->src].coverage.name; 1288*38fd1498Szrj else 1289*38fd1498Szrj file_name = canonicalize_name (file_name); 1290*38fd1498Szrj } 1291*38fd1498Szrj 1292*38fd1498Szrj if (flag_gcov_file && flag_intermediate_format) 1293*38fd1498Szrj { 1294*38fd1498Szrj /* Open the intermediate file. */ 1295*38fd1498Szrj gcov_intermediate_filename = get_gcov_intermediate_filename (file_name); 1296*38fd1498Szrj gcov_intermediate_file = fopen (gcov_intermediate_filename, "w"); 1297*38fd1498Szrj if (!gcov_intermediate_file) 1298*38fd1498Szrj { 1299*38fd1498Szrj fnotice (stderr, "Cannot open intermediate output file %s\n", 1300*38fd1498Szrj gcov_intermediate_filename); 1301*38fd1498Szrj return; 1302*38fd1498Szrj } 1303*38fd1498Szrj } 1304*38fd1498Szrj 1305*38fd1498Szrj for (vector<source_info>::iterator it = sources.begin (); 1306*38fd1498Szrj it != sources.end (); it++) 1307*38fd1498Szrj { 1308*38fd1498Szrj source_info *src = &(*it); 1309*38fd1498Szrj if (flag_relative_only) 1310*38fd1498Szrj { 1311*38fd1498Szrj /* Ignore this source, if it is an absolute path (after 1312*38fd1498Szrj source prefix removal). */ 1313*38fd1498Szrj char first = src->coverage.name[0]; 1314*38fd1498Szrj 1315*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 1316*38fd1498Szrj if (first && src->coverage.name[1] == ':') 1317*38fd1498Szrj first = src->coverage.name[2]; 1318*38fd1498Szrj #endif 1319*38fd1498Szrj if (IS_DIR_SEPARATOR (first)) 1320*38fd1498Szrj continue; 1321*38fd1498Szrj } 1322*38fd1498Szrj 1323*38fd1498Szrj accumulate_line_counts (src); 1324*38fd1498Szrj function_summary (&src->coverage, "File"); 1325*38fd1498Szrj total_lines += src->coverage.lines; 1326*38fd1498Szrj total_executed += src->coverage.lines_executed; 1327*38fd1498Szrj if (flag_gcov_file) 1328*38fd1498Szrj { 1329*38fd1498Szrj if (flag_intermediate_format) 1330*38fd1498Szrj /* Output the intermediate format without requiring source 1331*38fd1498Szrj files. This outputs a section to a *single* file. */ 1332*38fd1498Szrj output_intermediate_file (gcov_intermediate_file, src); 1333*38fd1498Szrj else 1334*38fd1498Szrj output_gcov_file (file_name, src); 1335*38fd1498Szrj fnotice (stdout, "\n"); 1336*38fd1498Szrj } 1337*38fd1498Szrj } 1338*38fd1498Szrj 1339*38fd1498Szrj if (flag_gcov_file && flag_intermediate_format) 1340*38fd1498Szrj { 1341*38fd1498Szrj /* Now we've finished writing the intermediate file. */ 1342*38fd1498Szrj fclose (gcov_intermediate_file); 1343*38fd1498Szrj XDELETEVEC (gcov_intermediate_filename); 1344*38fd1498Szrj } 1345*38fd1498Szrj 1346*38fd1498Szrj if (!file_name) 1347*38fd1498Szrj executed_summary (total_lines, total_executed); 1348*38fd1498Szrj } 1349*38fd1498Szrj 1350*38fd1498Szrj /* Release all memory used. */ 1351*38fd1498Szrj 1352*38fd1498Szrj static void 1353*38fd1498Szrj release_structures (void) 1354*38fd1498Szrj { 1355*38fd1498Szrj for (vector<function_info *>::iterator it = functions.begin (); 1356*38fd1498Szrj it != functions.end (); it++) 1357*38fd1498Szrj delete (*it); 1358*38fd1498Szrj 1359*38fd1498Szrj sources.resize (0); 1360*38fd1498Szrj names.resize (0); 1361*38fd1498Szrj functions.resize (0); 1362*38fd1498Szrj } 1363*38fd1498Szrj 1364*38fd1498Szrj /* Generate the names of the graph and data files. If OBJECT_DIRECTORY 1365*38fd1498Szrj is not specified, these are named from FILE_NAME sans extension. If 1366*38fd1498Szrj OBJECT_DIRECTORY is specified and is a directory, the files are in that 1367*38fd1498Szrj directory, but named from the basename of the FILE_NAME, sans extension. 1368*38fd1498Szrj Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file* 1369*38fd1498Szrj and the data files are named from that. */ 1370*38fd1498Szrj 1371*38fd1498Szrj static void 1372*38fd1498Szrj create_file_names (const char *file_name) 1373*38fd1498Szrj { 1374*38fd1498Szrj char *cptr; 1375*38fd1498Szrj char *name; 1376*38fd1498Szrj int length = strlen (file_name); 1377*38fd1498Szrj int base; 1378*38fd1498Szrj 1379*38fd1498Szrj /* Free previous file names. */ 1380*38fd1498Szrj free (bbg_file_name); 1381*38fd1498Szrj free (da_file_name); 1382*38fd1498Szrj da_file_name = bbg_file_name = NULL; 1383*38fd1498Szrj bbg_file_time = 0; 1384*38fd1498Szrj bbg_stamp = 0; 1385*38fd1498Szrj 1386*38fd1498Szrj if (object_directory && object_directory[0]) 1387*38fd1498Szrj { 1388*38fd1498Szrj struct stat status; 1389*38fd1498Szrj 1390*38fd1498Szrj length += strlen (object_directory) + 2; 1391*38fd1498Szrj name = XNEWVEC (char, length); 1392*38fd1498Szrj name[0] = 0; 1393*38fd1498Szrj 1394*38fd1498Szrj base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); 1395*38fd1498Szrj strcat (name, object_directory); 1396*38fd1498Szrj if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1]))) 1397*38fd1498Szrj strcat (name, "/"); 1398*38fd1498Szrj } 1399*38fd1498Szrj else 1400*38fd1498Szrj { 1401*38fd1498Szrj name = XNEWVEC (char, length + 1); 1402*38fd1498Szrj strcpy (name, file_name); 1403*38fd1498Szrj base = 0; 1404*38fd1498Szrj } 1405*38fd1498Szrj 1406*38fd1498Szrj if (base) 1407*38fd1498Szrj { 1408*38fd1498Szrj /* Append source file name. */ 1409*38fd1498Szrj const char *cptr = lbasename (file_name); 1410*38fd1498Szrj strcat (name, cptr ? cptr : file_name); 1411*38fd1498Szrj } 1412*38fd1498Szrj 1413*38fd1498Szrj /* Remove the extension. */ 1414*38fd1498Szrj cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.'); 1415*38fd1498Szrj if (cptr) 1416*38fd1498Szrj *cptr = 0; 1417*38fd1498Szrj 1418*38fd1498Szrj length = strlen (name); 1419*38fd1498Szrj 1420*38fd1498Szrj bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1); 1421*38fd1498Szrj strcpy (bbg_file_name, name); 1422*38fd1498Szrj strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); 1423*38fd1498Szrj 1424*38fd1498Szrj da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1); 1425*38fd1498Szrj strcpy (da_file_name, name); 1426*38fd1498Szrj strcpy (da_file_name + length, GCOV_DATA_SUFFIX); 1427*38fd1498Szrj 1428*38fd1498Szrj free (name); 1429*38fd1498Szrj return; 1430*38fd1498Szrj } 1431*38fd1498Szrj 1432*38fd1498Szrj /* Find or create a source file structure for FILE_NAME. Copies 1433*38fd1498Szrj FILE_NAME on creation */ 1434*38fd1498Szrj 1435*38fd1498Szrj static unsigned 1436*38fd1498Szrj find_source (const char *file_name) 1437*38fd1498Szrj { 1438*38fd1498Szrj char *canon; 1439*38fd1498Szrj unsigned idx; 1440*38fd1498Szrj struct stat status; 1441*38fd1498Szrj 1442*38fd1498Szrj if (!file_name) 1443*38fd1498Szrj file_name = "<unknown>"; 1444*38fd1498Szrj 1445*38fd1498Szrj name_map needle; 1446*38fd1498Szrj needle.name = file_name; 1447*38fd1498Szrj 1448*38fd1498Szrj vector<name_map>::iterator it = std::find (names.begin (), names.end (), 1449*38fd1498Szrj needle); 1450*38fd1498Szrj if (it != names.end ()) 1451*38fd1498Szrj { 1452*38fd1498Szrj idx = it->src; 1453*38fd1498Szrj goto check_date; 1454*38fd1498Szrj } 1455*38fd1498Szrj 1456*38fd1498Szrj /* Not found, try the canonical name. */ 1457*38fd1498Szrj canon = canonicalize_name (file_name); 1458*38fd1498Szrj needle.name = canon; 1459*38fd1498Szrj it = std::find (names.begin (), names.end (), needle); 1460*38fd1498Szrj if (it == names.end ()) 1461*38fd1498Szrj { 1462*38fd1498Szrj /* Not found with canonical name, create a new source. */ 1463*38fd1498Szrj source_info *src; 1464*38fd1498Szrj 1465*38fd1498Szrj idx = sources.size (); 1466*38fd1498Szrj needle = name_map (canon, idx); 1467*38fd1498Szrj names.push_back (needle); 1468*38fd1498Szrj 1469*38fd1498Szrj sources.push_back (source_info ()); 1470*38fd1498Szrj src = &sources.back (); 1471*38fd1498Szrj src->name = canon; 1472*38fd1498Szrj src->coverage.name = src->name; 1473*38fd1498Szrj src->index = idx; 1474*38fd1498Szrj if (source_length 1475*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 1476*38fd1498Szrj /* You lose if separators don't match exactly in the 1477*38fd1498Szrj prefix. */ 1478*38fd1498Szrj && !strncasecmp (source_prefix, src->coverage.name, source_length) 1479*38fd1498Szrj #else 1480*38fd1498Szrj && !strncmp (source_prefix, src->coverage.name, source_length) 1481*38fd1498Szrj #endif 1482*38fd1498Szrj && IS_DIR_SEPARATOR (src->coverage.name[source_length])) 1483*38fd1498Szrj src->coverage.name += source_length + 1; 1484*38fd1498Szrj if (!stat (src->name, &status)) 1485*38fd1498Szrj src->file_time = status.st_mtime; 1486*38fd1498Szrj } 1487*38fd1498Szrj else 1488*38fd1498Szrj idx = it->src; 1489*38fd1498Szrj 1490*38fd1498Szrj needle.name = file_name; 1491*38fd1498Szrj if (std::find (names.begin (), names.end (), needle) == names.end ()) 1492*38fd1498Szrj { 1493*38fd1498Szrj /* Append the non-canonical name. */ 1494*38fd1498Szrj names.push_back (name_map (xstrdup (file_name), idx)); 1495*38fd1498Szrj } 1496*38fd1498Szrj 1497*38fd1498Szrj /* Resort the name map. */ 1498*38fd1498Szrj std::sort (names.begin (), names.end ()); 1499*38fd1498Szrj 1500*38fd1498Szrj check_date: 1501*38fd1498Szrj if (sources[idx].file_time > bbg_file_time) 1502*38fd1498Szrj { 1503*38fd1498Szrj static int info_emitted; 1504*38fd1498Szrj 1505*38fd1498Szrj fnotice (stderr, "%s:source file is newer than notes file '%s'\n", 1506*38fd1498Szrj file_name, bbg_file_name); 1507*38fd1498Szrj if (!info_emitted) 1508*38fd1498Szrj { 1509*38fd1498Szrj fnotice (stderr, 1510*38fd1498Szrj "(the message is displayed only once per source file)\n"); 1511*38fd1498Szrj info_emitted = 1; 1512*38fd1498Szrj } 1513*38fd1498Szrj sources[idx].file_time = 0; 1514*38fd1498Szrj } 1515*38fd1498Szrj 1516*38fd1498Szrj return idx; 1517*38fd1498Szrj } 1518*38fd1498Szrj 1519*38fd1498Szrj /* Read the notes file. Save functions to FUNCTIONS global vector. */ 1520*38fd1498Szrj 1521*38fd1498Szrj static void 1522*38fd1498Szrj read_graph_file (void) 1523*38fd1498Szrj { 1524*38fd1498Szrj unsigned version; 1525*38fd1498Szrj unsigned current_tag = 0; 1526*38fd1498Szrj unsigned tag; 1527*38fd1498Szrj 1528*38fd1498Szrj if (!gcov_open (bbg_file_name, 1)) 1529*38fd1498Szrj { 1530*38fd1498Szrj fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name); 1531*38fd1498Szrj return; 1532*38fd1498Szrj } 1533*38fd1498Szrj bbg_file_time = gcov_time (); 1534*38fd1498Szrj if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) 1535*38fd1498Szrj { 1536*38fd1498Szrj fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name); 1537*38fd1498Szrj gcov_close (); 1538*38fd1498Szrj return; 1539*38fd1498Szrj } 1540*38fd1498Szrj 1541*38fd1498Szrj version = gcov_read_unsigned (); 1542*38fd1498Szrj if (version != GCOV_VERSION) 1543*38fd1498Szrj { 1544*38fd1498Szrj char v[4], e[4]; 1545*38fd1498Szrj 1546*38fd1498Szrj GCOV_UNSIGNED2STRING (v, version); 1547*38fd1498Szrj GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 1548*38fd1498Szrj 1549*38fd1498Szrj fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n", 1550*38fd1498Szrj bbg_file_name, v, e); 1551*38fd1498Szrj } 1552*38fd1498Szrj bbg_stamp = gcov_read_unsigned (); 1553*38fd1498Szrj bbg_supports_has_unexecuted_blocks = gcov_read_unsigned (); 1554*38fd1498Szrj 1555*38fd1498Szrj function_info *fn = NULL; 1556*38fd1498Szrj while ((tag = gcov_read_unsigned ())) 1557*38fd1498Szrj { 1558*38fd1498Szrj unsigned length = gcov_read_unsigned (); 1559*38fd1498Szrj gcov_position_t base = gcov_position (); 1560*38fd1498Szrj 1561*38fd1498Szrj if (tag == GCOV_TAG_FUNCTION) 1562*38fd1498Szrj { 1563*38fd1498Szrj char *function_name; 1564*38fd1498Szrj unsigned ident; 1565*38fd1498Szrj unsigned lineno_checksum, cfg_checksum; 1566*38fd1498Szrj 1567*38fd1498Szrj ident = gcov_read_unsigned (); 1568*38fd1498Szrj lineno_checksum = gcov_read_unsigned (); 1569*38fd1498Szrj cfg_checksum = gcov_read_unsigned (); 1570*38fd1498Szrj function_name = xstrdup (gcov_read_string ()); 1571*38fd1498Szrj unsigned artificial = gcov_read_unsigned (); 1572*38fd1498Szrj unsigned src_idx = find_source (gcov_read_string ()); 1573*38fd1498Szrj unsigned start_line = gcov_read_unsigned (); 1574*38fd1498Szrj unsigned start_column = gcov_read_unsigned (); 1575*38fd1498Szrj unsigned end_line = gcov_read_unsigned (); 1576*38fd1498Szrj 1577*38fd1498Szrj fn = new function_info (); 1578*38fd1498Szrj functions.push_back (fn); 1579*38fd1498Szrj fn->name = function_name; 1580*38fd1498Szrj if (flag_demangled_names) 1581*38fd1498Szrj { 1582*38fd1498Szrj fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS); 1583*38fd1498Szrj if (!fn->demangled_name) 1584*38fd1498Szrj fn->demangled_name = fn->name; 1585*38fd1498Szrj } 1586*38fd1498Szrj fn->ident = ident; 1587*38fd1498Szrj fn->lineno_checksum = lineno_checksum; 1588*38fd1498Szrj fn->cfg_checksum = cfg_checksum; 1589*38fd1498Szrj fn->src = src_idx; 1590*38fd1498Szrj fn->start_line = start_line; 1591*38fd1498Szrj fn->start_column = start_column; 1592*38fd1498Szrj fn->end_line = end_line; 1593*38fd1498Szrj fn->artificial = artificial; 1594*38fd1498Szrj 1595*38fd1498Szrj current_tag = tag; 1596*38fd1498Szrj } 1597*38fd1498Szrj else if (fn && tag == GCOV_TAG_BLOCKS) 1598*38fd1498Szrj { 1599*38fd1498Szrj if (!fn->blocks.empty ()) 1600*38fd1498Szrj fnotice (stderr, "%s:already seen blocks for '%s'\n", 1601*38fd1498Szrj bbg_file_name, fn->name); 1602*38fd1498Szrj else 1603*38fd1498Szrj fn->blocks.resize (gcov_read_unsigned ()); 1604*38fd1498Szrj } 1605*38fd1498Szrj else if (fn && tag == GCOV_TAG_ARCS) 1606*38fd1498Szrj { 1607*38fd1498Szrj unsigned src = gcov_read_unsigned (); 1608*38fd1498Szrj fn->blocks[src].id = src; 1609*38fd1498Szrj unsigned num_dests = GCOV_TAG_ARCS_NUM (length); 1610*38fd1498Szrj block_info *src_blk = &fn->blocks[src]; 1611*38fd1498Szrj unsigned mark_catches = 0; 1612*38fd1498Szrj struct arc_info *arc; 1613*38fd1498Szrj 1614*38fd1498Szrj if (src >= fn->blocks.size () || fn->blocks[src].succ) 1615*38fd1498Szrj goto corrupt; 1616*38fd1498Szrj 1617*38fd1498Szrj while (num_dests--) 1618*38fd1498Szrj { 1619*38fd1498Szrj unsigned dest = gcov_read_unsigned (); 1620*38fd1498Szrj unsigned flags = gcov_read_unsigned (); 1621*38fd1498Szrj 1622*38fd1498Szrj if (dest >= fn->blocks.size ()) 1623*38fd1498Szrj goto corrupt; 1624*38fd1498Szrj arc = XCNEW (arc_info); 1625*38fd1498Szrj 1626*38fd1498Szrj arc->dst = &fn->blocks[dest]; 1627*38fd1498Szrj arc->src = src_blk; 1628*38fd1498Szrj 1629*38fd1498Szrj arc->count = 0; 1630*38fd1498Szrj arc->count_valid = 0; 1631*38fd1498Szrj arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); 1632*38fd1498Szrj arc->fake = !!(flags & GCOV_ARC_FAKE); 1633*38fd1498Szrj arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); 1634*38fd1498Szrj 1635*38fd1498Szrj arc->succ_next = src_blk->succ; 1636*38fd1498Szrj src_blk->succ = arc; 1637*38fd1498Szrj src_blk->num_succ++; 1638*38fd1498Szrj 1639*38fd1498Szrj arc->pred_next = fn->blocks[dest].pred; 1640*38fd1498Szrj fn->blocks[dest].pred = arc; 1641*38fd1498Szrj fn->blocks[dest].num_pred++; 1642*38fd1498Szrj 1643*38fd1498Szrj if (arc->fake) 1644*38fd1498Szrj { 1645*38fd1498Szrj if (src) 1646*38fd1498Szrj { 1647*38fd1498Szrj /* Exceptional exit from this function, the 1648*38fd1498Szrj source block must be a call. */ 1649*38fd1498Szrj fn->blocks[src].is_call_site = 1; 1650*38fd1498Szrj arc->is_call_non_return = 1; 1651*38fd1498Szrj mark_catches = 1; 1652*38fd1498Szrj } 1653*38fd1498Szrj else 1654*38fd1498Szrj { 1655*38fd1498Szrj /* Non-local return from a callee of this 1656*38fd1498Szrj function. The destination block is a setjmp. */ 1657*38fd1498Szrj arc->is_nonlocal_return = 1; 1658*38fd1498Szrj fn->blocks[dest].is_nonlocal_return = 1; 1659*38fd1498Szrj } 1660*38fd1498Szrj } 1661*38fd1498Szrj 1662*38fd1498Szrj if (!arc->on_tree) 1663*38fd1498Szrj fn->counts.push_back (0); 1664*38fd1498Szrj } 1665*38fd1498Szrj 1666*38fd1498Szrj if (mark_catches) 1667*38fd1498Szrj { 1668*38fd1498Szrj /* We have a fake exit from this block. The other 1669*38fd1498Szrj non-fall through exits must be to catch handlers. 1670*38fd1498Szrj Mark them as catch arcs. */ 1671*38fd1498Szrj 1672*38fd1498Szrj for (arc = src_blk->succ; arc; arc = arc->succ_next) 1673*38fd1498Szrj if (!arc->fake && !arc->fall_through) 1674*38fd1498Szrj { 1675*38fd1498Szrj arc->is_throw = 1; 1676*38fd1498Szrj fn->has_catch = 1; 1677*38fd1498Szrj } 1678*38fd1498Szrj } 1679*38fd1498Szrj } 1680*38fd1498Szrj else if (fn && tag == GCOV_TAG_LINES) 1681*38fd1498Szrj { 1682*38fd1498Szrj unsigned blockno = gcov_read_unsigned (); 1683*38fd1498Szrj block_info *block = &fn->blocks[blockno]; 1684*38fd1498Szrj 1685*38fd1498Szrj if (blockno >= fn->blocks.size ()) 1686*38fd1498Szrj goto corrupt; 1687*38fd1498Szrj 1688*38fd1498Szrj while (true) 1689*38fd1498Szrj { 1690*38fd1498Szrj unsigned lineno = gcov_read_unsigned (); 1691*38fd1498Szrj 1692*38fd1498Szrj if (lineno) 1693*38fd1498Szrj block->locations.back ().lines.push_back (lineno); 1694*38fd1498Szrj else 1695*38fd1498Szrj { 1696*38fd1498Szrj const char *file_name = gcov_read_string (); 1697*38fd1498Szrj 1698*38fd1498Szrj if (!file_name) 1699*38fd1498Szrj break; 1700*38fd1498Szrj block->locations.push_back (block_location_info 1701*38fd1498Szrj (find_source (file_name))); 1702*38fd1498Szrj } 1703*38fd1498Szrj } 1704*38fd1498Szrj } 1705*38fd1498Szrj else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) 1706*38fd1498Szrj { 1707*38fd1498Szrj fn = NULL; 1708*38fd1498Szrj current_tag = 0; 1709*38fd1498Szrj } 1710*38fd1498Szrj gcov_sync (base, length); 1711*38fd1498Szrj if (gcov_is_error ()) 1712*38fd1498Szrj { 1713*38fd1498Szrj corrupt:; 1714*38fd1498Szrj fnotice (stderr, "%s:corrupted\n", bbg_file_name); 1715*38fd1498Szrj break; 1716*38fd1498Szrj } 1717*38fd1498Szrj } 1718*38fd1498Szrj gcov_close (); 1719*38fd1498Szrj 1720*38fd1498Szrj if (functions.empty ()) 1721*38fd1498Szrj fnotice (stderr, "%s:no functions found\n", bbg_file_name); 1722*38fd1498Szrj } 1723*38fd1498Szrj 1724*38fd1498Szrj /* Reads profiles from the count file and attach to each 1725*38fd1498Szrj function. Return nonzero if fatal error. */ 1726*38fd1498Szrj 1727*38fd1498Szrj static int 1728*38fd1498Szrj read_count_file (void) 1729*38fd1498Szrj { 1730*38fd1498Szrj unsigned ix; 1731*38fd1498Szrj unsigned version; 1732*38fd1498Szrj unsigned tag; 1733*38fd1498Szrj function_info *fn = NULL; 1734*38fd1498Szrj int error = 0; 1735*38fd1498Szrj 1736*38fd1498Szrj if (!gcov_open (da_file_name, 1)) 1737*38fd1498Szrj { 1738*38fd1498Szrj fnotice (stderr, "%s:cannot open data file, assuming not executed\n", 1739*38fd1498Szrj da_file_name); 1740*38fd1498Szrj no_data_file = 1; 1741*38fd1498Szrj return 0; 1742*38fd1498Szrj } 1743*38fd1498Szrj if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) 1744*38fd1498Szrj { 1745*38fd1498Szrj fnotice (stderr, "%s:not a gcov data file\n", da_file_name); 1746*38fd1498Szrj cleanup:; 1747*38fd1498Szrj gcov_close (); 1748*38fd1498Szrj return 1; 1749*38fd1498Szrj } 1750*38fd1498Szrj version = gcov_read_unsigned (); 1751*38fd1498Szrj if (version != GCOV_VERSION) 1752*38fd1498Szrj { 1753*38fd1498Szrj char v[4], e[4]; 1754*38fd1498Szrj 1755*38fd1498Szrj GCOV_UNSIGNED2STRING (v, version); 1756*38fd1498Szrj GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 1757*38fd1498Szrj 1758*38fd1498Szrj fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n", 1759*38fd1498Szrj da_file_name, v, e); 1760*38fd1498Szrj } 1761*38fd1498Szrj tag = gcov_read_unsigned (); 1762*38fd1498Szrj if (tag != bbg_stamp) 1763*38fd1498Szrj { 1764*38fd1498Szrj fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name); 1765*38fd1498Szrj goto cleanup; 1766*38fd1498Szrj } 1767*38fd1498Szrj 1768*38fd1498Szrj while ((tag = gcov_read_unsigned ())) 1769*38fd1498Szrj { 1770*38fd1498Szrj unsigned length = gcov_read_unsigned (); 1771*38fd1498Szrj unsigned long base = gcov_position (); 1772*38fd1498Szrj 1773*38fd1498Szrj if (tag == GCOV_TAG_PROGRAM_SUMMARY) 1774*38fd1498Szrj { 1775*38fd1498Szrj struct gcov_summary summary; 1776*38fd1498Szrj gcov_read_summary (&summary); 1777*38fd1498Szrj object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs; 1778*38fd1498Szrj program_count++; 1779*38fd1498Szrj } 1780*38fd1498Szrj else if (tag == GCOV_TAG_FUNCTION && !length) 1781*38fd1498Szrj ; /* placeholder */ 1782*38fd1498Szrj else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH) 1783*38fd1498Szrj { 1784*38fd1498Szrj unsigned ident; 1785*38fd1498Szrj 1786*38fd1498Szrj /* Try to find the function in the list. To speed up the 1787*38fd1498Szrj search, first start from the last function found. */ 1788*38fd1498Szrj ident = gcov_read_unsigned (); 1789*38fd1498Szrj 1790*38fd1498Szrj fn = NULL; 1791*38fd1498Szrj for (vector<function_info *>::reverse_iterator it 1792*38fd1498Szrj = functions.rbegin (); it != functions.rend (); it++) 1793*38fd1498Szrj { 1794*38fd1498Szrj if ((*it)->ident == ident) 1795*38fd1498Szrj { 1796*38fd1498Szrj fn = *it; 1797*38fd1498Szrj break; 1798*38fd1498Szrj } 1799*38fd1498Szrj } 1800*38fd1498Szrj 1801*38fd1498Szrj if (!fn) 1802*38fd1498Szrj ; 1803*38fd1498Szrj else if (gcov_read_unsigned () != fn->lineno_checksum 1804*38fd1498Szrj || gcov_read_unsigned () != fn->cfg_checksum) 1805*38fd1498Szrj { 1806*38fd1498Szrj mismatch:; 1807*38fd1498Szrj fnotice (stderr, "%s:profile mismatch for '%s'\n", 1808*38fd1498Szrj da_file_name, fn->name); 1809*38fd1498Szrj goto cleanup; 1810*38fd1498Szrj } 1811*38fd1498Szrj } 1812*38fd1498Szrj else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) 1813*38fd1498Szrj { 1814*38fd1498Szrj if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ())) 1815*38fd1498Szrj goto mismatch; 1816*38fd1498Szrj 1817*38fd1498Szrj for (ix = 0; ix != fn->counts.size (); ix++) 1818*38fd1498Szrj fn->counts[ix] += gcov_read_counter (); 1819*38fd1498Szrj } 1820*38fd1498Szrj gcov_sync (base, length); 1821*38fd1498Szrj if ((error = gcov_is_error ())) 1822*38fd1498Szrj { 1823*38fd1498Szrj fnotice (stderr, 1824*38fd1498Szrj error < 0 1825*38fd1498Szrj ? N_("%s:overflowed\n") 1826*38fd1498Szrj : N_("%s:corrupted\n"), 1827*38fd1498Szrj da_file_name); 1828*38fd1498Szrj goto cleanup; 1829*38fd1498Szrj } 1830*38fd1498Szrj } 1831*38fd1498Szrj 1832*38fd1498Szrj gcov_close (); 1833*38fd1498Szrj return 0; 1834*38fd1498Szrj } 1835*38fd1498Szrj 1836*38fd1498Szrj /* Solve the flow graph. Propagate counts from the instrumented arcs 1837*38fd1498Szrj to the blocks and the uninstrumented arcs. */ 1838*38fd1498Szrj 1839*38fd1498Szrj static void 1840*38fd1498Szrj solve_flow_graph (function_info *fn) 1841*38fd1498Szrj { 1842*38fd1498Szrj unsigned ix; 1843*38fd1498Szrj arc_info *arc; 1844*38fd1498Szrj gcov_type *count_ptr = &fn->counts.front (); 1845*38fd1498Szrj block_info *blk; 1846*38fd1498Szrj block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */ 1847*38fd1498Szrj block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */ 1848*38fd1498Szrj 1849*38fd1498Szrj /* The arcs were built in reverse order. Fix that now. */ 1850*38fd1498Szrj for (ix = fn->blocks.size (); ix--;) 1851*38fd1498Szrj { 1852*38fd1498Szrj arc_info *arc_p, *arc_n; 1853*38fd1498Szrj 1854*38fd1498Szrj for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; 1855*38fd1498Szrj arc_p = arc, arc = arc_n) 1856*38fd1498Szrj { 1857*38fd1498Szrj arc_n = arc->succ_next; 1858*38fd1498Szrj arc->succ_next = arc_p; 1859*38fd1498Szrj } 1860*38fd1498Szrj fn->blocks[ix].succ = arc_p; 1861*38fd1498Szrj 1862*38fd1498Szrj for (arc_p = NULL, arc = fn->blocks[ix].pred; arc; 1863*38fd1498Szrj arc_p = arc, arc = arc_n) 1864*38fd1498Szrj { 1865*38fd1498Szrj arc_n = arc->pred_next; 1866*38fd1498Szrj arc->pred_next = arc_p; 1867*38fd1498Szrj } 1868*38fd1498Szrj fn->blocks[ix].pred = arc_p; 1869*38fd1498Szrj } 1870*38fd1498Szrj 1871*38fd1498Szrj if (fn->blocks.size () < 2) 1872*38fd1498Szrj fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n", 1873*38fd1498Szrj bbg_file_name, fn->name); 1874*38fd1498Szrj else 1875*38fd1498Szrj { 1876*38fd1498Szrj if (fn->blocks[ENTRY_BLOCK].num_pred) 1877*38fd1498Szrj fnotice (stderr, "%s:'%s' has arcs to entry block\n", 1878*38fd1498Szrj bbg_file_name, fn->name); 1879*38fd1498Szrj else 1880*38fd1498Szrj /* We can't deduce the entry block counts from the lack of 1881*38fd1498Szrj predecessors. */ 1882*38fd1498Szrj fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0; 1883*38fd1498Szrj 1884*38fd1498Szrj if (fn->blocks[EXIT_BLOCK].num_succ) 1885*38fd1498Szrj fnotice (stderr, "%s:'%s' has arcs from exit block\n", 1886*38fd1498Szrj bbg_file_name, fn->name); 1887*38fd1498Szrj else 1888*38fd1498Szrj /* Likewise, we can't deduce exit block counts from the lack 1889*38fd1498Szrj of its successors. */ 1890*38fd1498Szrj fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0; 1891*38fd1498Szrj } 1892*38fd1498Szrj 1893*38fd1498Szrj /* Propagate the measured counts, this must be done in the same 1894*38fd1498Szrj order as the code in profile.c */ 1895*38fd1498Szrj for (unsigned i = 0; i < fn->blocks.size (); i++) 1896*38fd1498Szrj { 1897*38fd1498Szrj blk = &fn->blocks[i]; 1898*38fd1498Szrj block_info const *prev_dst = NULL; 1899*38fd1498Szrj int out_of_order = 0; 1900*38fd1498Szrj int non_fake_succ = 0; 1901*38fd1498Szrj 1902*38fd1498Szrj for (arc = blk->succ; arc; arc = arc->succ_next) 1903*38fd1498Szrj { 1904*38fd1498Szrj if (!arc->fake) 1905*38fd1498Szrj non_fake_succ++; 1906*38fd1498Szrj 1907*38fd1498Szrj if (!arc->on_tree) 1908*38fd1498Szrj { 1909*38fd1498Szrj if (count_ptr) 1910*38fd1498Szrj arc->count = *count_ptr++; 1911*38fd1498Szrj arc->count_valid = 1; 1912*38fd1498Szrj blk->num_succ--; 1913*38fd1498Szrj arc->dst->num_pred--; 1914*38fd1498Szrj } 1915*38fd1498Szrj if (prev_dst && prev_dst > arc->dst) 1916*38fd1498Szrj out_of_order = 1; 1917*38fd1498Szrj prev_dst = arc->dst; 1918*38fd1498Szrj } 1919*38fd1498Szrj if (non_fake_succ == 1) 1920*38fd1498Szrj { 1921*38fd1498Szrj /* If there is only one non-fake exit, it is an 1922*38fd1498Szrj unconditional branch. */ 1923*38fd1498Szrj for (arc = blk->succ; arc; arc = arc->succ_next) 1924*38fd1498Szrj if (!arc->fake) 1925*38fd1498Szrj { 1926*38fd1498Szrj arc->is_unconditional = 1; 1927*38fd1498Szrj /* If this block is instrumenting a call, it might be 1928*38fd1498Szrj an artificial block. It is not artificial if it has 1929*38fd1498Szrj a non-fallthrough exit, or the destination of this 1930*38fd1498Szrj arc has more than one entry. Mark the destination 1931*38fd1498Szrj block as a return site, if none of those conditions 1932*38fd1498Szrj hold. */ 1933*38fd1498Szrj if (blk->is_call_site && arc->fall_through 1934*38fd1498Szrj && arc->dst->pred == arc && !arc->pred_next) 1935*38fd1498Szrj arc->dst->is_call_return = 1; 1936*38fd1498Szrj } 1937*38fd1498Szrj } 1938*38fd1498Szrj 1939*38fd1498Szrj /* Sort the successor arcs into ascending dst order. profile.c 1940*38fd1498Szrj normally produces arcs in the right order, but sometimes with 1941*38fd1498Szrj one or two out of order. We're not using a particularly 1942*38fd1498Szrj smart sort. */ 1943*38fd1498Szrj if (out_of_order) 1944*38fd1498Szrj { 1945*38fd1498Szrj arc_info *start = blk->succ; 1946*38fd1498Szrj unsigned changes = 1; 1947*38fd1498Szrj 1948*38fd1498Szrj while (changes) 1949*38fd1498Szrj { 1950*38fd1498Szrj arc_info *arc, *arc_p, *arc_n; 1951*38fd1498Szrj 1952*38fd1498Szrj changes = 0; 1953*38fd1498Szrj for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) 1954*38fd1498Szrj { 1955*38fd1498Szrj if (arc->dst > arc_n->dst) 1956*38fd1498Szrj { 1957*38fd1498Szrj changes = 1; 1958*38fd1498Szrj if (arc_p) 1959*38fd1498Szrj arc_p->succ_next = arc_n; 1960*38fd1498Szrj else 1961*38fd1498Szrj start = arc_n; 1962*38fd1498Szrj arc->succ_next = arc_n->succ_next; 1963*38fd1498Szrj arc_n->succ_next = arc; 1964*38fd1498Szrj arc_p = arc_n; 1965*38fd1498Szrj } 1966*38fd1498Szrj else 1967*38fd1498Szrj { 1968*38fd1498Szrj arc_p = arc; 1969*38fd1498Szrj arc = arc_n; 1970*38fd1498Szrj } 1971*38fd1498Szrj } 1972*38fd1498Szrj } 1973*38fd1498Szrj blk->succ = start; 1974*38fd1498Szrj } 1975*38fd1498Szrj 1976*38fd1498Szrj /* Place it on the invalid chain, it will be ignored if that's 1977*38fd1498Szrj wrong. */ 1978*38fd1498Szrj blk->invalid_chain = 1; 1979*38fd1498Szrj blk->chain = invalid_blocks; 1980*38fd1498Szrj invalid_blocks = blk; 1981*38fd1498Szrj } 1982*38fd1498Szrj 1983*38fd1498Szrj while (invalid_blocks || valid_blocks) 1984*38fd1498Szrj { 1985*38fd1498Szrj while ((blk = invalid_blocks)) 1986*38fd1498Szrj { 1987*38fd1498Szrj gcov_type total = 0; 1988*38fd1498Szrj const arc_info *arc; 1989*38fd1498Szrj 1990*38fd1498Szrj invalid_blocks = blk->chain; 1991*38fd1498Szrj blk->invalid_chain = 0; 1992*38fd1498Szrj if (!blk->num_succ) 1993*38fd1498Szrj for (arc = blk->succ; arc; arc = arc->succ_next) 1994*38fd1498Szrj total += arc->count; 1995*38fd1498Szrj else if (!blk->num_pred) 1996*38fd1498Szrj for (arc = blk->pred; arc; arc = arc->pred_next) 1997*38fd1498Szrj total += arc->count; 1998*38fd1498Szrj else 1999*38fd1498Szrj continue; 2000*38fd1498Szrj 2001*38fd1498Szrj blk->count = total; 2002*38fd1498Szrj blk->count_valid = 1; 2003*38fd1498Szrj blk->chain = valid_blocks; 2004*38fd1498Szrj blk->valid_chain = 1; 2005*38fd1498Szrj valid_blocks = blk; 2006*38fd1498Szrj } 2007*38fd1498Szrj while ((blk = valid_blocks)) 2008*38fd1498Szrj { 2009*38fd1498Szrj gcov_type total; 2010*38fd1498Szrj arc_info *arc, *inv_arc; 2011*38fd1498Szrj 2012*38fd1498Szrj valid_blocks = blk->chain; 2013*38fd1498Szrj blk->valid_chain = 0; 2014*38fd1498Szrj if (blk->num_succ == 1) 2015*38fd1498Szrj { 2016*38fd1498Szrj block_info *dst; 2017*38fd1498Szrj 2018*38fd1498Szrj total = blk->count; 2019*38fd1498Szrj inv_arc = NULL; 2020*38fd1498Szrj for (arc = blk->succ; arc; arc = arc->succ_next) 2021*38fd1498Szrj { 2022*38fd1498Szrj total -= arc->count; 2023*38fd1498Szrj if (!arc->count_valid) 2024*38fd1498Szrj inv_arc = arc; 2025*38fd1498Szrj } 2026*38fd1498Szrj dst = inv_arc->dst; 2027*38fd1498Szrj inv_arc->count_valid = 1; 2028*38fd1498Szrj inv_arc->count = total; 2029*38fd1498Szrj blk->num_succ--; 2030*38fd1498Szrj dst->num_pred--; 2031*38fd1498Szrj if (dst->count_valid) 2032*38fd1498Szrj { 2033*38fd1498Szrj if (dst->num_pred == 1 && !dst->valid_chain) 2034*38fd1498Szrj { 2035*38fd1498Szrj dst->chain = valid_blocks; 2036*38fd1498Szrj dst->valid_chain = 1; 2037*38fd1498Szrj valid_blocks = dst; 2038*38fd1498Szrj } 2039*38fd1498Szrj } 2040*38fd1498Szrj else 2041*38fd1498Szrj { 2042*38fd1498Szrj if (!dst->num_pred && !dst->invalid_chain) 2043*38fd1498Szrj { 2044*38fd1498Szrj dst->chain = invalid_blocks; 2045*38fd1498Szrj dst->invalid_chain = 1; 2046*38fd1498Szrj invalid_blocks = dst; 2047*38fd1498Szrj } 2048*38fd1498Szrj } 2049*38fd1498Szrj } 2050*38fd1498Szrj if (blk->num_pred == 1) 2051*38fd1498Szrj { 2052*38fd1498Szrj block_info *src; 2053*38fd1498Szrj 2054*38fd1498Szrj total = blk->count; 2055*38fd1498Szrj inv_arc = NULL; 2056*38fd1498Szrj for (arc = blk->pred; arc; arc = arc->pred_next) 2057*38fd1498Szrj { 2058*38fd1498Szrj total -= arc->count; 2059*38fd1498Szrj if (!arc->count_valid) 2060*38fd1498Szrj inv_arc = arc; 2061*38fd1498Szrj } 2062*38fd1498Szrj src = inv_arc->src; 2063*38fd1498Szrj inv_arc->count_valid = 1; 2064*38fd1498Szrj inv_arc->count = total; 2065*38fd1498Szrj blk->num_pred--; 2066*38fd1498Szrj src->num_succ--; 2067*38fd1498Szrj if (src->count_valid) 2068*38fd1498Szrj { 2069*38fd1498Szrj if (src->num_succ == 1 && !src->valid_chain) 2070*38fd1498Szrj { 2071*38fd1498Szrj src->chain = valid_blocks; 2072*38fd1498Szrj src->valid_chain = 1; 2073*38fd1498Szrj valid_blocks = src; 2074*38fd1498Szrj } 2075*38fd1498Szrj } 2076*38fd1498Szrj else 2077*38fd1498Szrj { 2078*38fd1498Szrj if (!src->num_succ && !src->invalid_chain) 2079*38fd1498Szrj { 2080*38fd1498Szrj src->chain = invalid_blocks; 2081*38fd1498Szrj src->invalid_chain = 1; 2082*38fd1498Szrj invalid_blocks = src; 2083*38fd1498Szrj } 2084*38fd1498Szrj } 2085*38fd1498Szrj } 2086*38fd1498Szrj } 2087*38fd1498Szrj } 2088*38fd1498Szrj 2089*38fd1498Szrj /* If the graph has been correctly solved, every block will have a 2090*38fd1498Szrj valid count. */ 2091*38fd1498Szrj for (unsigned i = 0; ix < fn->blocks.size (); i++) 2092*38fd1498Szrj if (!fn->blocks[i].count_valid) 2093*38fd1498Szrj { 2094*38fd1498Szrj fnotice (stderr, "%s:graph is unsolvable for '%s'\n", 2095*38fd1498Szrj bbg_file_name, fn->name); 2096*38fd1498Szrj break; 2097*38fd1498Szrj } 2098*38fd1498Szrj } 2099*38fd1498Szrj 2100*38fd1498Szrj /* Mark all the blocks only reachable via an incoming catch. */ 2101*38fd1498Szrj 2102*38fd1498Szrj static void 2103*38fd1498Szrj find_exception_blocks (function_info *fn) 2104*38fd1498Szrj { 2105*38fd1498Szrj unsigned ix; 2106*38fd1498Szrj block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ()); 2107*38fd1498Szrj 2108*38fd1498Szrj /* First mark all blocks as exceptional. */ 2109*38fd1498Szrj for (ix = fn->blocks.size (); ix--;) 2110*38fd1498Szrj fn->blocks[ix].exceptional = 1; 2111*38fd1498Szrj 2112*38fd1498Szrj /* Now mark all the blocks reachable via non-fake edges */ 2113*38fd1498Szrj queue[0] = &fn->blocks[0]; 2114*38fd1498Szrj queue[0]->exceptional = 0; 2115*38fd1498Szrj for (ix = 1; ix;) 2116*38fd1498Szrj { 2117*38fd1498Szrj block_info *block = queue[--ix]; 2118*38fd1498Szrj const arc_info *arc; 2119*38fd1498Szrj 2120*38fd1498Szrj for (arc = block->succ; arc; arc = arc->succ_next) 2121*38fd1498Szrj if (!arc->fake && !arc->is_throw && arc->dst->exceptional) 2122*38fd1498Szrj { 2123*38fd1498Szrj arc->dst->exceptional = 0; 2124*38fd1498Szrj queue[ix++] = arc->dst; 2125*38fd1498Szrj } 2126*38fd1498Szrj } 2127*38fd1498Szrj } 2128*38fd1498Szrj 2129*38fd1498Szrj 2130*38fd1498Szrj /* Increment totals in COVERAGE according to arc ARC. */ 2131*38fd1498Szrj 2132*38fd1498Szrj static void 2133*38fd1498Szrj add_branch_counts (coverage_info *coverage, const arc_info *arc) 2134*38fd1498Szrj { 2135*38fd1498Szrj if (arc->is_call_non_return) 2136*38fd1498Szrj { 2137*38fd1498Szrj coverage->calls++; 2138*38fd1498Szrj if (arc->src->count) 2139*38fd1498Szrj coverage->calls_executed++; 2140*38fd1498Szrj } 2141*38fd1498Szrj else if (!arc->is_unconditional) 2142*38fd1498Szrj { 2143*38fd1498Szrj coverage->branches++; 2144*38fd1498Szrj if (arc->src->count) 2145*38fd1498Szrj coverage->branches_executed++; 2146*38fd1498Szrj if (arc->count) 2147*38fd1498Szrj coverage->branches_taken++; 2148*38fd1498Szrj } 2149*38fd1498Szrj } 2150*38fd1498Szrj 2151*38fd1498Szrj /* Format COUNT, if flag_human_readable_numbers is set, return it human 2152*38fd1498Szrj readable format. */ 2153*38fd1498Szrj 2154*38fd1498Szrj static char const * 2155*38fd1498Szrj format_count (gcov_type count) 2156*38fd1498Szrj { 2157*38fd1498Szrj static char buffer[64]; 2158*38fd1498Szrj const char *units = " kMGTPEZY"; 2159*38fd1498Szrj 2160*38fd1498Szrj if (count < 1000 || !flag_human_readable_numbers) 2161*38fd1498Szrj { 2162*38fd1498Szrj sprintf (buffer, "%" PRId64, count); 2163*38fd1498Szrj return buffer; 2164*38fd1498Szrj } 2165*38fd1498Szrj 2166*38fd1498Szrj unsigned i; 2167*38fd1498Szrj gcov_type divisor = 1; 2168*38fd1498Szrj for (i = 0; units[i+1]; i++, divisor *= 1000) 2169*38fd1498Szrj { 2170*38fd1498Szrj if (count + divisor / 2 < 1000 * divisor) 2171*38fd1498Szrj break; 2172*38fd1498Szrj } 2173*38fd1498Szrj gcov_type r = (count + divisor / 2) / divisor; 2174*38fd1498Szrj sprintf (buffer, "%" PRId64 "%c", r, units[i]); 2175*38fd1498Szrj return buffer; 2176*38fd1498Szrj } 2177*38fd1498Szrj 2178*38fd1498Szrj /* Format a GCOV_TYPE integer as either a percent ratio, or absolute 2179*38fd1498Szrj count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. 2180*38fd1498Szrj If DP is zero, no decimal point is printed. Only print 100% when 2181*38fd1498Szrj TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply 2182*38fd1498Szrj format TOP. Return pointer to a static string. */ 2183*38fd1498Szrj 2184*38fd1498Szrj static char const * 2185*38fd1498Szrj format_gcov (gcov_type top, gcov_type bottom, int dp) 2186*38fd1498Szrj { 2187*38fd1498Szrj static char buffer[20]; 2188*38fd1498Szrj 2189*38fd1498Szrj /* Handle invalid values that would result in a misleading value. */ 2190*38fd1498Szrj if (bottom != 0 && top > bottom && dp >= 0) 2191*38fd1498Szrj { 2192*38fd1498Szrj sprintf (buffer, "NAN %%"); 2193*38fd1498Szrj return buffer; 2194*38fd1498Szrj } 2195*38fd1498Szrj 2196*38fd1498Szrj if (dp >= 0) 2197*38fd1498Szrj { 2198*38fd1498Szrj float ratio = bottom ? (float)top / bottom : 0; 2199*38fd1498Szrj int ix; 2200*38fd1498Szrj unsigned limit = 100; 2201*38fd1498Szrj unsigned percent; 2202*38fd1498Szrj 2203*38fd1498Szrj for (ix = dp; ix--; ) 2204*38fd1498Szrj limit *= 10; 2205*38fd1498Szrj 2206*38fd1498Szrj percent = (unsigned) (ratio * limit + (float)0.5); 2207*38fd1498Szrj if (percent <= 0 && top) 2208*38fd1498Szrj percent = 1; 2209*38fd1498Szrj else if (percent >= limit && top != bottom) 2210*38fd1498Szrj percent = limit - 1; 2211*38fd1498Szrj ix = sprintf (buffer, "%.*u%%", dp + 1, percent); 2212*38fd1498Szrj if (dp) 2213*38fd1498Szrj { 2214*38fd1498Szrj dp++; 2215*38fd1498Szrj do 2216*38fd1498Szrj { 2217*38fd1498Szrj buffer[ix+1] = buffer[ix]; 2218*38fd1498Szrj ix--; 2219*38fd1498Szrj } 2220*38fd1498Szrj while (dp--); 2221*38fd1498Szrj buffer[ix + 1] = '.'; 2222*38fd1498Szrj } 2223*38fd1498Szrj } 2224*38fd1498Szrj else 2225*38fd1498Szrj return format_count (top); 2226*38fd1498Szrj 2227*38fd1498Szrj return buffer; 2228*38fd1498Szrj } 2229*38fd1498Szrj 2230*38fd1498Szrj /* Summary of execution */ 2231*38fd1498Szrj 2232*38fd1498Szrj static void 2233*38fd1498Szrj executed_summary (unsigned lines, unsigned executed) 2234*38fd1498Szrj { 2235*38fd1498Szrj if (lines) 2236*38fd1498Szrj fnotice (stdout, "Lines executed:%s of %d\n", 2237*38fd1498Szrj format_gcov (executed, lines, 2), lines); 2238*38fd1498Szrj else 2239*38fd1498Szrj fnotice (stdout, "No executable lines\n"); 2240*38fd1498Szrj } 2241*38fd1498Szrj 2242*38fd1498Szrj /* Output summary info for a function or file. */ 2243*38fd1498Szrj 2244*38fd1498Szrj static void 2245*38fd1498Szrj function_summary (const coverage_info *coverage, const char *title) 2246*38fd1498Szrj { 2247*38fd1498Szrj fnotice (stdout, "%s '%s'\n", title, coverage->name); 2248*38fd1498Szrj executed_summary (coverage->lines, coverage->lines_executed); 2249*38fd1498Szrj 2250*38fd1498Szrj if (flag_branches) 2251*38fd1498Szrj { 2252*38fd1498Szrj if (coverage->branches) 2253*38fd1498Szrj { 2254*38fd1498Szrj fnotice (stdout, "Branches executed:%s of %d\n", 2255*38fd1498Szrj format_gcov (coverage->branches_executed, 2256*38fd1498Szrj coverage->branches, 2), 2257*38fd1498Szrj coverage->branches); 2258*38fd1498Szrj fnotice (stdout, "Taken at least once:%s of %d\n", 2259*38fd1498Szrj format_gcov (coverage->branches_taken, 2260*38fd1498Szrj coverage->branches, 2), 2261*38fd1498Szrj coverage->branches); 2262*38fd1498Szrj } 2263*38fd1498Szrj else 2264*38fd1498Szrj fnotice (stdout, "No branches\n"); 2265*38fd1498Szrj if (coverage->calls) 2266*38fd1498Szrj fnotice (stdout, "Calls executed:%s of %d\n", 2267*38fd1498Szrj format_gcov (coverage->calls_executed, coverage->calls, 2), 2268*38fd1498Szrj coverage->calls); 2269*38fd1498Szrj else 2270*38fd1498Szrj fnotice (stdout, "No calls\n"); 2271*38fd1498Szrj } 2272*38fd1498Szrj } 2273*38fd1498Szrj 2274*38fd1498Szrj /* Canonicalize the filename NAME by canonicalizing directory 2275*38fd1498Szrj separators, eliding . components and resolving .. components 2276*38fd1498Szrj appropriately. Always returns a unique string. */ 2277*38fd1498Szrj 2278*38fd1498Szrj static char * 2279*38fd1498Szrj canonicalize_name (const char *name) 2280*38fd1498Szrj { 2281*38fd1498Szrj /* The canonical name cannot be longer than the incoming name. */ 2282*38fd1498Szrj char *result = XNEWVEC (char, strlen (name) + 1); 2283*38fd1498Szrj const char *base = name, *probe; 2284*38fd1498Szrj char *ptr = result; 2285*38fd1498Szrj char *dd_base; 2286*38fd1498Szrj int slash = 0; 2287*38fd1498Szrj 2288*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 2289*38fd1498Szrj if (base[0] && base[1] == ':') 2290*38fd1498Szrj { 2291*38fd1498Szrj result[0] = base[0]; 2292*38fd1498Szrj result[1] = ':'; 2293*38fd1498Szrj base += 2; 2294*38fd1498Szrj ptr += 2; 2295*38fd1498Szrj } 2296*38fd1498Szrj #endif 2297*38fd1498Szrj for (dd_base = ptr; *base; base = probe) 2298*38fd1498Szrj { 2299*38fd1498Szrj size_t len; 2300*38fd1498Szrj 2301*38fd1498Szrj for (probe = base; *probe; probe++) 2302*38fd1498Szrj if (IS_DIR_SEPARATOR (*probe)) 2303*38fd1498Szrj break; 2304*38fd1498Szrj 2305*38fd1498Szrj len = probe - base; 2306*38fd1498Szrj if (len == 1 && base[0] == '.') 2307*38fd1498Szrj /* Elide a '.' directory */ 2308*38fd1498Szrj ; 2309*38fd1498Szrj else if (len == 2 && base[0] == '.' && base[1] == '.') 2310*38fd1498Szrj { 2311*38fd1498Szrj /* '..', we can only elide it and the previous directory, if 2312*38fd1498Szrj we're not a symlink. */ 2313*38fd1498Szrj struct stat ATTRIBUTE_UNUSED buf; 2314*38fd1498Szrj 2315*38fd1498Szrj *ptr = 0; 2316*38fd1498Szrj if (dd_base == ptr 2317*38fd1498Szrj #if defined (S_ISLNK) 2318*38fd1498Szrj /* S_ISLNK is not POSIX.1-1996. */ 2319*38fd1498Szrj || stat (result, &buf) || S_ISLNK (buf.st_mode) 2320*38fd1498Szrj #endif 2321*38fd1498Szrj ) 2322*38fd1498Szrj { 2323*38fd1498Szrj /* Cannot elide, or unreadable or a symlink. */ 2324*38fd1498Szrj dd_base = ptr + 2 + slash; 2325*38fd1498Szrj goto regular; 2326*38fd1498Szrj } 2327*38fd1498Szrj while (ptr != dd_base && *ptr != '/') 2328*38fd1498Szrj ptr--; 2329*38fd1498Szrj slash = ptr != result; 2330*38fd1498Szrj } 2331*38fd1498Szrj else 2332*38fd1498Szrj { 2333*38fd1498Szrj regular: 2334*38fd1498Szrj /* Regular pathname component. */ 2335*38fd1498Szrj if (slash) 2336*38fd1498Szrj *ptr++ = '/'; 2337*38fd1498Szrj memcpy (ptr, base, len); 2338*38fd1498Szrj ptr += len; 2339*38fd1498Szrj slash = 1; 2340*38fd1498Szrj } 2341*38fd1498Szrj 2342*38fd1498Szrj for (; IS_DIR_SEPARATOR (*probe); probe++) 2343*38fd1498Szrj continue; 2344*38fd1498Szrj } 2345*38fd1498Szrj *ptr = 0; 2346*38fd1498Szrj 2347*38fd1498Szrj return result; 2348*38fd1498Szrj } 2349*38fd1498Szrj 2350*38fd1498Szrj /* Print hex representation of 16 bytes from SUM and write it to BUFFER. */ 2351*38fd1498Szrj 2352*38fd1498Szrj static void 2353*38fd1498Szrj md5sum_to_hex (const char *sum, char *buffer) 2354*38fd1498Szrj { 2355*38fd1498Szrj for (unsigned i = 0; i < 16; i++) 2356*38fd1498Szrj sprintf (buffer + (2 * i), "%02x", (unsigned char)sum[i]); 2357*38fd1498Szrj } 2358*38fd1498Szrj 2359*38fd1498Szrj /* Generate an output file name. INPUT_NAME is the canonicalized main 2360*38fd1498Szrj input file and SRC_NAME is the canonicalized file name. 2361*38fd1498Szrj LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With 2362*38fd1498Szrj long_output_names we prepend the processed name of the input file 2363*38fd1498Szrj to each output name (except when the current source file is the 2364*38fd1498Szrj input file, so you don't get a double concatenation). The two 2365*38fd1498Szrj components are separated by '##'. With preserve_paths we create a 2366*38fd1498Szrj filename from all path components of the source file, replacing '/' 2367*38fd1498Szrj with '#', and .. with '^', without it we simply take the basename 2368*38fd1498Szrj component. (Remember, the canonicalized name will already have 2369*38fd1498Szrj elided '.' components and converted \\ separators.) */ 2370*38fd1498Szrj 2371*38fd1498Szrj static char * 2372*38fd1498Szrj make_gcov_file_name (const char *input_name, const char *src_name) 2373*38fd1498Szrj { 2374*38fd1498Szrj char *ptr; 2375*38fd1498Szrj char *result; 2376*38fd1498Szrj 2377*38fd1498Szrj if (flag_long_names && input_name && strcmp (src_name, input_name)) 2378*38fd1498Szrj { 2379*38fd1498Szrj /* Generate the input filename part. */ 2380*38fd1498Szrj result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10); 2381*38fd1498Szrj 2382*38fd1498Szrj ptr = result; 2383*38fd1498Szrj ptr = mangle_name (input_name, ptr); 2384*38fd1498Szrj ptr[0] = ptr[1] = '#'; 2385*38fd1498Szrj ptr += 2; 2386*38fd1498Szrj } 2387*38fd1498Szrj else 2388*38fd1498Szrj { 2389*38fd1498Szrj result = XNEWVEC (char, strlen (src_name) + 10); 2390*38fd1498Szrj ptr = result; 2391*38fd1498Szrj } 2392*38fd1498Szrj 2393*38fd1498Szrj ptr = mangle_name (src_name, ptr); 2394*38fd1498Szrj strcpy (ptr, ".gcov"); 2395*38fd1498Szrj 2396*38fd1498Szrj /* When hashing filenames, we shorten them by only using the filename 2397*38fd1498Szrj component and appending a hash of the full (mangled) pathname. */ 2398*38fd1498Szrj if (flag_hash_filenames) 2399*38fd1498Szrj { 2400*38fd1498Szrj md5_ctx ctx; 2401*38fd1498Szrj char md5sum[16]; 2402*38fd1498Szrj char md5sum_hex[33]; 2403*38fd1498Szrj 2404*38fd1498Szrj md5_init_ctx (&ctx); 2405*38fd1498Szrj md5_process_bytes (src_name, strlen (src_name), &ctx); 2406*38fd1498Szrj md5_finish_ctx (&ctx, md5sum); 2407*38fd1498Szrj md5sum_to_hex (md5sum, md5sum_hex); 2408*38fd1498Szrj free (result); 2409*38fd1498Szrj 2410*38fd1498Szrj result = XNEWVEC (char, strlen (src_name) + 50); 2411*38fd1498Szrj ptr = result; 2412*38fd1498Szrj ptr = mangle_name (src_name, ptr); 2413*38fd1498Szrj ptr[0] = ptr[1] = '#'; 2414*38fd1498Szrj ptr += 2; 2415*38fd1498Szrj memcpy (ptr, md5sum_hex, 32); 2416*38fd1498Szrj ptr += 32; 2417*38fd1498Szrj strcpy (ptr, ".gcov"); 2418*38fd1498Szrj } 2419*38fd1498Szrj 2420*38fd1498Szrj return result; 2421*38fd1498Szrj } 2422*38fd1498Szrj 2423*38fd1498Szrj static char * 2424*38fd1498Szrj mangle_name (char const *base, char *ptr) 2425*38fd1498Szrj { 2426*38fd1498Szrj size_t len; 2427*38fd1498Szrj 2428*38fd1498Szrj /* Generate the source filename part. */ 2429*38fd1498Szrj if (!flag_preserve_paths) 2430*38fd1498Szrj { 2431*38fd1498Szrj base = lbasename (base); 2432*38fd1498Szrj len = strlen (base); 2433*38fd1498Szrj memcpy (ptr, base, len); 2434*38fd1498Szrj ptr += len; 2435*38fd1498Szrj } 2436*38fd1498Szrj else 2437*38fd1498Szrj { 2438*38fd1498Szrj /* Convert '/' to '#', convert '..' to '^', 2439*38fd1498Szrj convert ':' to '~' on DOS based file system. */ 2440*38fd1498Szrj const char *probe; 2441*38fd1498Szrj 2442*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM 2443*38fd1498Szrj if (base[0] && base[1] == ':') 2444*38fd1498Szrj { 2445*38fd1498Szrj ptr[0] = base[0]; 2446*38fd1498Szrj ptr[1] = '~'; 2447*38fd1498Szrj ptr += 2; 2448*38fd1498Szrj base += 2; 2449*38fd1498Szrj } 2450*38fd1498Szrj #endif 2451*38fd1498Szrj for (; *base; base = probe) 2452*38fd1498Szrj { 2453*38fd1498Szrj size_t len; 2454*38fd1498Szrj 2455*38fd1498Szrj for (probe = base; *probe; probe++) 2456*38fd1498Szrj if (*probe == '/') 2457*38fd1498Szrj break; 2458*38fd1498Szrj len = probe - base; 2459*38fd1498Szrj if (len == 2 && base[0] == '.' && base[1] == '.') 2460*38fd1498Szrj *ptr++ = '^'; 2461*38fd1498Szrj else 2462*38fd1498Szrj { 2463*38fd1498Szrj memcpy (ptr, base, len); 2464*38fd1498Szrj ptr += len; 2465*38fd1498Szrj } 2466*38fd1498Szrj if (*probe) 2467*38fd1498Szrj { 2468*38fd1498Szrj *ptr++ = '#'; 2469*38fd1498Szrj probe++; 2470*38fd1498Szrj } 2471*38fd1498Szrj } 2472*38fd1498Szrj } 2473*38fd1498Szrj 2474*38fd1498Szrj return ptr; 2475*38fd1498Szrj } 2476*38fd1498Szrj 2477*38fd1498Szrj /* Scan through the bb_data for each line in the block, increment 2478*38fd1498Szrj the line number execution count indicated by the execution count of 2479*38fd1498Szrj the appropriate basic block. */ 2480*38fd1498Szrj 2481*38fd1498Szrj static void 2482*38fd1498Szrj add_line_counts (coverage_info *coverage, function_info *fn) 2483*38fd1498Szrj { 2484*38fd1498Szrj bool has_any_line = false; 2485*38fd1498Szrj /* Scan each basic block. */ 2486*38fd1498Szrj for (unsigned ix = 0; ix != fn->blocks.size (); ix++) 2487*38fd1498Szrj { 2488*38fd1498Szrj line_info *line = NULL; 2489*38fd1498Szrj block_info *block = &fn->blocks[ix]; 2490*38fd1498Szrj if (block->count && ix && ix + 1 != fn->blocks.size ()) 2491*38fd1498Szrj fn->blocks_executed++; 2492*38fd1498Szrj for (unsigned i = 0; i < block->locations.size (); i++) 2493*38fd1498Szrj { 2494*38fd1498Szrj unsigned src_idx = block->locations[i].source_file_idx; 2495*38fd1498Szrj vector<unsigned> &lines = block->locations[i].lines; 2496*38fd1498Szrj 2497*38fd1498Szrj block->cycle.arc = NULL; 2498*38fd1498Szrj block->cycle.ident = ~0U; 2499*38fd1498Szrj 2500*38fd1498Szrj for (unsigned j = 0; j < lines.size (); j++) 2501*38fd1498Szrj { 2502*38fd1498Szrj unsigned ln = lines[j]; 2503*38fd1498Szrj 2504*38fd1498Szrj /* Line belongs to a function that is in a group. */ 2505*38fd1498Szrj if (fn->group_line_p (ln, src_idx)) 2506*38fd1498Szrj { 2507*38fd1498Szrj gcc_assert (lines[j] - fn->start_line < fn->lines.size ()); 2508*38fd1498Szrj line = &(fn->lines[lines[j] - fn->start_line]); 2509*38fd1498Szrj line->exists = 1; 2510*38fd1498Szrj if (!block->exceptional) 2511*38fd1498Szrj { 2512*38fd1498Szrj line->unexceptional = 1; 2513*38fd1498Szrj if (block->count == 0) 2514*38fd1498Szrj line->has_unexecuted_block = 1; 2515*38fd1498Szrj } 2516*38fd1498Szrj line->count += block->count; 2517*38fd1498Szrj } 2518*38fd1498Szrj else 2519*38fd1498Szrj { 2520*38fd1498Szrj gcc_assert (ln < sources[src_idx].lines.size ()); 2521*38fd1498Szrj line = &(sources[src_idx].lines[ln]); 2522*38fd1498Szrj if (coverage) 2523*38fd1498Szrj { 2524*38fd1498Szrj if (!line->exists) 2525*38fd1498Szrj coverage->lines++; 2526*38fd1498Szrj if (!line->count && block->count) 2527*38fd1498Szrj coverage->lines_executed++; 2528*38fd1498Szrj } 2529*38fd1498Szrj line->exists = 1; 2530*38fd1498Szrj if (!block->exceptional) 2531*38fd1498Szrj { 2532*38fd1498Szrj line->unexceptional = 1; 2533*38fd1498Szrj if (block->count == 0) 2534*38fd1498Szrj line->has_unexecuted_block = 1; 2535*38fd1498Szrj } 2536*38fd1498Szrj line->count += block->count; 2537*38fd1498Szrj } 2538*38fd1498Szrj } 2539*38fd1498Szrj 2540*38fd1498Szrj has_any_line = true; 2541*38fd1498Szrj 2542*38fd1498Szrj if (!ix || ix + 1 == fn->blocks.size ()) 2543*38fd1498Szrj /* Entry or exit block. */; 2544*38fd1498Szrj else if (line != NULL) 2545*38fd1498Szrj { 2546*38fd1498Szrj line->blocks.push_back (block); 2547*38fd1498Szrj 2548*38fd1498Szrj if (flag_branches) 2549*38fd1498Szrj { 2550*38fd1498Szrj arc_info *arc; 2551*38fd1498Szrj 2552*38fd1498Szrj for (arc = block->succ; arc; arc = arc->succ_next) 2553*38fd1498Szrj line->branches.push_back (arc); 2554*38fd1498Szrj } 2555*38fd1498Szrj } 2556*38fd1498Szrj } 2557*38fd1498Szrj } 2558*38fd1498Szrj 2559*38fd1498Szrj if (!has_any_line) 2560*38fd1498Szrj fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name); 2561*38fd1498Szrj } 2562*38fd1498Szrj 2563*38fd1498Szrj /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE 2564*38fd1498Szrj is set to true, update source file summary. */ 2565*38fd1498Szrj 2566*38fd1498Szrj static void accumulate_line_info (line_info *line, source_info *src, 2567*38fd1498Szrj bool add_coverage) 2568*38fd1498Szrj { 2569*38fd1498Szrj if (add_coverage) 2570*38fd1498Szrj for (vector<arc_info *>::iterator it = line->branches.begin (); 2571*38fd1498Szrj it != line->branches.end (); it++) 2572*38fd1498Szrj add_branch_counts (&src->coverage, *it); 2573*38fd1498Szrj 2574*38fd1498Szrj if (!line->blocks.empty ()) 2575*38fd1498Szrj { 2576*38fd1498Szrj /* The user expects the line count to be the number of times 2577*38fd1498Szrj a line has been executed. Simply summing the block count 2578*38fd1498Szrj will give an artificially high number. The Right Thing 2579*38fd1498Szrj is to sum the entry counts to the graph of blocks on this 2580*38fd1498Szrj line, then find the elementary cycles of the local graph 2581*38fd1498Szrj and add the transition counts of those cycles. */ 2582*38fd1498Szrj gcov_type count = 0; 2583*38fd1498Szrj 2584*38fd1498Szrj /* Cycle detection. */ 2585*38fd1498Szrj for (vector<block_info *>::iterator it = line->blocks.begin (); 2586*38fd1498Szrj it != line->blocks.end (); it++) 2587*38fd1498Szrj { 2588*38fd1498Szrj for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next) 2589*38fd1498Szrj if (!line->has_block (arc->src)) 2590*38fd1498Szrj count += arc->count; 2591*38fd1498Szrj for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next) 2592*38fd1498Szrj arc->cs_count = arc->count; 2593*38fd1498Szrj } 2594*38fd1498Szrj 2595*38fd1498Szrj /* Now, add the count of loops entirely on this line. */ 2596*38fd1498Szrj count += get_cycles_count (*line); 2597*38fd1498Szrj line->count = count; 2598*38fd1498Szrj } 2599*38fd1498Szrj 2600*38fd1498Szrj if (line->exists && add_coverage) 2601*38fd1498Szrj { 2602*38fd1498Szrj src->coverage.lines++; 2603*38fd1498Szrj if (line->count) 2604*38fd1498Szrj src->coverage.lines_executed++; 2605*38fd1498Szrj } 2606*38fd1498Szrj } 2607*38fd1498Szrj 2608*38fd1498Szrj /* Accumulate the line counts of a file. */ 2609*38fd1498Szrj 2610*38fd1498Szrj static void 2611*38fd1498Szrj accumulate_line_counts (source_info *src) 2612*38fd1498Szrj { 2613*38fd1498Szrj /* First work on group functions. */ 2614*38fd1498Szrj for (vector<function_info *>::iterator it = src->functions.begin (); 2615*38fd1498Szrj it != src->functions.end (); it++) 2616*38fd1498Szrj { 2617*38fd1498Szrj function_info *fn = *it; 2618*38fd1498Szrj 2619*38fd1498Szrj if (fn->src != src->index || !fn->is_group) 2620*38fd1498Szrj continue; 2621*38fd1498Szrj 2622*38fd1498Szrj for (vector<line_info>::iterator it2 = fn->lines.begin (); 2623*38fd1498Szrj it2 != fn->lines.end (); it2++) 2624*38fd1498Szrj { 2625*38fd1498Szrj line_info *line = &(*it2); 2626*38fd1498Szrj accumulate_line_info (line, src, false); 2627*38fd1498Szrj } 2628*38fd1498Szrj } 2629*38fd1498Szrj 2630*38fd1498Szrj /* Work on global lines that line in source file SRC. */ 2631*38fd1498Szrj for (vector<line_info>::iterator it = src->lines.begin (); 2632*38fd1498Szrj it != src->lines.end (); it++) 2633*38fd1498Szrj accumulate_line_info (&(*it), src, true); 2634*38fd1498Szrj 2635*38fd1498Szrj /* If not using intermediate mode, sum lines of group functions and 2636*38fd1498Szrj add them to lines that live in a source file. */ 2637*38fd1498Szrj if (!flag_intermediate_format) 2638*38fd1498Szrj for (vector<function_info *>::iterator it = src->functions.begin (); 2639*38fd1498Szrj it != src->functions.end (); it++) 2640*38fd1498Szrj { 2641*38fd1498Szrj function_info *fn = *it; 2642*38fd1498Szrj 2643*38fd1498Szrj if (fn->src != src->index || !fn->is_group) 2644*38fd1498Szrj continue; 2645*38fd1498Szrj 2646*38fd1498Szrj for (unsigned i = 0; i < fn->lines.size (); i++) 2647*38fd1498Szrj { 2648*38fd1498Szrj line_info *fn_line = &fn->lines[i]; 2649*38fd1498Szrj if (fn_line->exists) 2650*38fd1498Szrj { 2651*38fd1498Szrj unsigned ln = fn->start_line + i; 2652*38fd1498Szrj line_info *src_line = &src->lines[ln]; 2653*38fd1498Szrj 2654*38fd1498Szrj if (!src_line->exists) 2655*38fd1498Szrj src->coverage.lines++; 2656*38fd1498Szrj if (!src_line->count && fn_line->count) 2657*38fd1498Szrj src->coverage.lines_executed++; 2658*38fd1498Szrj 2659*38fd1498Szrj src_line->count += fn_line->count; 2660*38fd1498Szrj src_line->exists = 1; 2661*38fd1498Szrj 2662*38fd1498Szrj if (fn_line->has_unexecuted_block) 2663*38fd1498Szrj src_line->has_unexecuted_block = 1; 2664*38fd1498Szrj 2665*38fd1498Szrj if (fn_line->unexceptional) 2666*38fd1498Szrj src_line->unexceptional = 1; 2667*38fd1498Szrj } 2668*38fd1498Szrj } 2669*38fd1498Szrj } 2670*38fd1498Szrj } 2671*38fd1498Szrj 2672*38fd1498Szrj /* Output information about ARC number IX. Returns nonzero if 2673*38fd1498Szrj anything is output. */ 2674*38fd1498Szrj 2675*38fd1498Szrj static int 2676*38fd1498Szrj output_branch_count (FILE *gcov_file, int ix, const arc_info *arc) 2677*38fd1498Szrj { 2678*38fd1498Szrj if (arc->is_call_non_return) 2679*38fd1498Szrj { 2680*38fd1498Szrj if (arc->src->count) 2681*38fd1498Szrj { 2682*38fd1498Szrj fnotice (gcov_file, "call %2d returned %s\n", ix, 2683*38fd1498Szrj format_gcov (arc->src->count - arc->count, 2684*38fd1498Szrj arc->src->count, -flag_counts)); 2685*38fd1498Szrj } 2686*38fd1498Szrj else 2687*38fd1498Szrj fnotice (gcov_file, "call %2d never executed\n", ix); 2688*38fd1498Szrj } 2689*38fd1498Szrj else if (!arc->is_unconditional) 2690*38fd1498Szrj { 2691*38fd1498Szrj if (arc->src->count) 2692*38fd1498Szrj fnotice (gcov_file, "branch %2d taken %s%s", ix, 2693*38fd1498Szrj format_gcov (arc->count, arc->src->count, -flag_counts), 2694*38fd1498Szrj arc->fall_through ? " (fallthrough)" 2695*38fd1498Szrj : arc->is_throw ? " (throw)" : ""); 2696*38fd1498Szrj else 2697*38fd1498Szrj fnotice (gcov_file, "branch %2d never executed", ix); 2698*38fd1498Szrj 2699*38fd1498Szrj if (flag_verbose) 2700*38fd1498Szrj fnotice (gcov_file, " (BB %d)", arc->dst->id); 2701*38fd1498Szrj 2702*38fd1498Szrj fnotice (gcov_file, "\n"); 2703*38fd1498Szrj } 2704*38fd1498Szrj else if (flag_unconditional && !arc->dst->is_call_return) 2705*38fd1498Szrj { 2706*38fd1498Szrj if (arc->src->count) 2707*38fd1498Szrj fnotice (gcov_file, "unconditional %2d taken %s\n", ix, 2708*38fd1498Szrj format_gcov (arc->count, arc->src->count, -flag_counts)); 2709*38fd1498Szrj else 2710*38fd1498Szrj fnotice (gcov_file, "unconditional %2d never executed\n", ix); 2711*38fd1498Szrj } 2712*38fd1498Szrj else 2713*38fd1498Szrj return 0; 2714*38fd1498Szrj return 1; 2715*38fd1498Szrj } 2716*38fd1498Szrj 2717*38fd1498Szrj static const char * 2718*38fd1498Szrj read_line (FILE *file) 2719*38fd1498Szrj { 2720*38fd1498Szrj static char *string; 2721*38fd1498Szrj static size_t string_len; 2722*38fd1498Szrj size_t pos = 0; 2723*38fd1498Szrj char *ptr; 2724*38fd1498Szrj 2725*38fd1498Szrj if (!string_len) 2726*38fd1498Szrj { 2727*38fd1498Szrj string_len = 200; 2728*38fd1498Szrj string = XNEWVEC (char, string_len); 2729*38fd1498Szrj } 2730*38fd1498Szrj 2731*38fd1498Szrj while ((ptr = fgets (string + pos, string_len - pos, file))) 2732*38fd1498Szrj { 2733*38fd1498Szrj size_t len = strlen (string + pos); 2734*38fd1498Szrj 2735*38fd1498Szrj if (len && string[pos + len - 1] == '\n') 2736*38fd1498Szrj { 2737*38fd1498Szrj string[pos + len - 1] = 0; 2738*38fd1498Szrj return string; 2739*38fd1498Szrj } 2740*38fd1498Szrj pos += len; 2741*38fd1498Szrj /* If the file contains NUL characters or an incomplete 2742*38fd1498Szrj last line, which can happen more than once in one run, 2743*38fd1498Szrj we have to avoid doubling the STRING_LEN unnecessarily. */ 2744*38fd1498Szrj if (pos > string_len / 2) 2745*38fd1498Szrj { 2746*38fd1498Szrj string_len *= 2; 2747*38fd1498Szrj string = XRESIZEVEC (char, string, string_len); 2748*38fd1498Szrj } 2749*38fd1498Szrj } 2750*38fd1498Szrj 2751*38fd1498Szrj return pos ? string : NULL; 2752*38fd1498Szrj } 2753*38fd1498Szrj 2754*38fd1498Szrj /* Pad string S with spaces from left to have total width equal to 9. */ 2755*38fd1498Szrj 2756*38fd1498Szrj static void 2757*38fd1498Szrj pad_count_string (string &s) 2758*38fd1498Szrj { 2759*38fd1498Szrj if (s.size () < 9) 2760*38fd1498Szrj s.insert (0, 9 - s.size (), ' '); 2761*38fd1498Szrj } 2762*38fd1498Szrj 2763*38fd1498Szrj /* Print GCOV line beginning to F stream. If EXISTS is set to true, the 2764*38fd1498Szrj line exists in source file. UNEXCEPTIONAL indicated that it's not in 2765*38fd1498Szrj an exceptional statement. The output is printed for LINE_NUM of given 2766*38fd1498Szrj COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are 2767*38fd1498Szrj used to indicate non-executed blocks. */ 2768*38fd1498Szrj 2769*38fd1498Szrj static void 2770*38fd1498Szrj output_line_beginning (FILE *f, bool exists, bool unexceptional, 2771*38fd1498Szrj bool has_unexecuted_block, 2772*38fd1498Szrj gcov_type count, unsigned line_num, 2773*38fd1498Szrj const char *exceptional_string, 2774*38fd1498Szrj const char *unexceptional_string) 2775*38fd1498Szrj { 2776*38fd1498Szrj string s; 2777*38fd1498Szrj if (exists) 2778*38fd1498Szrj { 2779*38fd1498Szrj if (count > 0) 2780*38fd1498Szrj { 2781*38fd1498Szrj s = format_gcov (count, 0, -1); 2782*38fd1498Szrj if (has_unexecuted_block 2783*38fd1498Szrj && bbg_supports_has_unexecuted_blocks) 2784*38fd1498Szrj { 2785*38fd1498Szrj if (flag_use_colors) 2786*38fd1498Szrj { 2787*38fd1498Szrj pad_count_string (s); 2788*38fd1498Szrj s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA 2789*38fd1498Szrj COLOR_SEPARATOR COLOR_FG_WHITE)); 2790*38fd1498Szrj s += SGR_RESET; 2791*38fd1498Szrj } 2792*38fd1498Szrj else 2793*38fd1498Szrj s += "*"; 2794*38fd1498Szrj } 2795*38fd1498Szrj pad_count_string (s); 2796*38fd1498Szrj } 2797*38fd1498Szrj else 2798*38fd1498Szrj { 2799*38fd1498Szrj if (flag_use_colors) 2800*38fd1498Szrj { 2801*38fd1498Szrj s = "0"; 2802*38fd1498Szrj pad_count_string (s); 2803*38fd1498Szrj if (unexceptional) 2804*38fd1498Szrj s.insert (0, SGR_SEQ (COLOR_BG_RED 2805*38fd1498Szrj COLOR_SEPARATOR COLOR_FG_WHITE)); 2806*38fd1498Szrj else 2807*38fd1498Szrj s.insert (0, SGR_SEQ (COLOR_BG_CYAN 2808*38fd1498Szrj COLOR_SEPARATOR COLOR_FG_WHITE)); 2809*38fd1498Szrj s += SGR_RESET; 2810*38fd1498Szrj } 2811*38fd1498Szrj else 2812*38fd1498Szrj { 2813*38fd1498Szrj s = unexceptional ? unexceptional_string : exceptional_string; 2814*38fd1498Szrj pad_count_string (s); 2815*38fd1498Szrj } 2816*38fd1498Szrj } 2817*38fd1498Szrj } 2818*38fd1498Szrj else 2819*38fd1498Szrj { 2820*38fd1498Szrj s = "-"; 2821*38fd1498Szrj pad_count_string (s); 2822*38fd1498Szrj } 2823*38fd1498Szrj 2824*38fd1498Szrj fprintf (f, "%s:%5u", s.c_str (), line_num); 2825*38fd1498Szrj } 2826*38fd1498Szrj 2827*38fd1498Szrj static void 2828*38fd1498Szrj print_source_line (FILE *f, const vector<const char *> &source_lines, 2829*38fd1498Szrj unsigned line) 2830*38fd1498Szrj { 2831*38fd1498Szrj gcc_assert (line >= 1); 2832*38fd1498Szrj gcc_assert (line <= source_lines.size ()); 2833*38fd1498Szrj 2834*38fd1498Szrj fprintf (f, ":%s\n", source_lines[line - 1]); 2835*38fd1498Szrj } 2836*38fd1498Szrj 2837*38fd1498Szrj /* Output line details for LINE and print it to F file. LINE lives on 2838*38fd1498Szrj LINE_NUM. */ 2839*38fd1498Szrj 2840*38fd1498Szrj static void 2841*38fd1498Szrj output_line_details (FILE *f, const line_info *line, unsigned line_num) 2842*38fd1498Szrj { 2843*38fd1498Szrj if (flag_all_blocks) 2844*38fd1498Szrj { 2845*38fd1498Szrj arc_info *arc; 2846*38fd1498Szrj int ix, jx; 2847*38fd1498Szrj 2848*38fd1498Szrj ix = jx = 0; 2849*38fd1498Szrj for (vector<block_info *>::const_iterator it = line->blocks.begin (); 2850*38fd1498Szrj it != line->blocks.end (); it++) 2851*38fd1498Szrj { 2852*38fd1498Szrj if (!(*it)->is_call_return) 2853*38fd1498Szrj { 2854*38fd1498Szrj output_line_beginning (f, line->exists, 2855*38fd1498Szrj (*it)->exceptional, false, 2856*38fd1498Szrj (*it)->count, line_num, 2857*38fd1498Szrj "%%%%%", "$$$$$"); 2858*38fd1498Szrj fprintf (f, "-block %2d", ix++); 2859*38fd1498Szrj if (flag_verbose) 2860*38fd1498Szrj fprintf (f, " (BB %u)", (*it)->id); 2861*38fd1498Szrj fprintf (f, "\n"); 2862*38fd1498Szrj } 2863*38fd1498Szrj if (flag_branches) 2864*38fd1498Szrj for (arc = (*it)->succ; arc; arc = arc->succ_next) 2865*38fd1498Szrj jx += output_branch_count (f, jx, arc); 2866*38fd1498Szrj } 2867*38fd1498Szrj } 2868*38fd1498Szrj else if (flag_branches) 2869*38fd1498Szrj { 2870*38fd1498Szrj int ix; 2871*38fd1498Szrj 2872*38fd1498Szrj ix = 0; 2873*38fd1498Szrj for (vector<arc_info *>::const_iterator it = line->branches.begin (); 2874*38fd1498Szrj it != line->branches.end (); it++) 2875*38fd1498Szrj ix += output_branch_count (f, ix, (*it)); 2876*38fd1498Szrj } 2877*38fd1498Szrj } 2878*38fd1498Szrj 2879*38fd1498Szrj /* Output detail statistics about function FN to file F. */ 2880*38fd1498Szrj 2881*38fd1498Szrj static void 2882*38fd1498Szrj output_function_details (FILE *f, const function_info *fn) 2883*38fd1498Szrj { 2884*38fd1498Szrj if (!flag_branches) 2885*38fd1498Szrj return; 2886*38fd1498Szrj 2887*38fd1498Szrj arc_info *arc = fn->blocks[EXIT_BLOCK].pred; 2888*38fd1498Szrj gcov_type return_count = fn->blocks[EXIT_BLOCK].count; 2889*38fd1498Szrj gcov_type called_count = fn->blocks[ENTRY_BLOCK].count; 2890*38fd1498Szrj 2891*38fd1498Szrj for (; arc; arc = arc->pred_next) 2892*38fd1498Szrj if (arc->fake) 2893*38fd1498Szrj return_count -= arc->count; 2894*38fd1498Szrj 2895*38fd1498Szrj fprintf (f, "function %s", 2896*38fd1498Szrj flag_demangled_names ? fn->demangled_name : fn->name); 2897*38fd1498Szrj fprintf (f, " called %s", 2898*38fd1498Szrj format_gcov (called_count, 0, -1)); 2899*38fd1498Szrj fprintf (f, " returned %s", 2900*38fd1498Szrj format_gcov (return_count, called_count, 0)); 2901*38fd1498Szrj fprintf (f, " blocks executed %s", 2902*38fd1498Szrj format_gcov (fn->blocks_executed, fn->blocks.size () - 2, 2903*38fd1498Szrj 0)); 2904*38fd1498Szrj fprintf (f, "\n"); 2905*38fd1498Szrj } 2906*38fd1498Szrj 2907*38fd1498Szrj /* Read in the source file one line at a time, and output that line to 2908*38fd1498Szrj the gcov file preceded by its execution count and other 2909*38fd1498Szrj information. */ 2910*38fd1498Szrj 2911*38fd1498Szrj static void 2912*38fd1498Szrj output_lines (FILE *gcov_file, const source_info *src) 2913*38fd1498Szrj { 2914*38fd1498Szrj #define DEFAULT_LINE_START " -: 0:" 2915*38fd1498Szrj #define FN_SEPARATOR "------------------\n" 2916*38fd1498Szrj 2917*38fd1498Szrj FILE *source_file; 2918*38fd1498Szrj const char *retval; 2919*38fd1498Szrj 2920*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name); 2921*38fd1498Szrj if (!multiple_files) 2922*38fd1498Szrj { 2923*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name); 2924*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n", 2925*38fd1498Szrj no_data_file ? "-" : da_file_name); 2926*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs); 2927*38fd1498Szrj } 2928*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Programs:%u\n", program_count); 2929*38fd1498Szrj 2930*38fd1498Szrj source_file = fopen (src->name, "r"); 2931*38fd1498Szrj if (!source_file) 2932*38fd1498Szrj fnotice (stderr, "Cannot open source file %s\n", src->name); 2933*38fd1498Szrj else if (src->file_time == 0) 2934*38fd1498Szrj fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n"); 2935*38fd1498Szrj 2936*38fd1498Szrj vector<const char *> source_lines; 2937*38fd1498Szrj if (source_file) 2938*38fd1498Szrj while ((retval = read_line (source_file)) != NULL) 2939*38fd1498Szrj source_lines.push_back (xstrdup (retval)); 2940*38fd1498Szrj 2941*38fd1498Szrj unsigned line_start_group = 0; 2942*38fd1498Szrj vector<function_info *> fns; 2943*38fd1498Szrj 2944*38fd1498Szrj for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++) 2945*38fd1498Szrj { 2946*38fd1498Szrj if (line_num >= src->lines.size ()) 2947*38fd1498Szrj { 2948*38fd1498Szrj fprintf (gcov_file, "%9s:%5u", "-", line_num); 2949*38fd1498Szrj print_source_line (gcov_file, source_lines, line_num); 2950*38fd1498Szrj continue; 2951*38fd1498Szrj } 2952*38fd1498Szrj 2953*38fd1498Szrj const line_info *line = &src->lines[line_num]; 2954*38fd1498Szrj 2955*38fd1498Szrj if (line_start_group == 0) 2956*38fd1498Szrj { 2957*38fd1498Szrj fns = src->get_functions_at_location (line_num); 2958*38fd1498Szrj if (fns.size () > 1) 2959*38fd1498Szrj { 2960*38fd1498Szrj /* It's possible to have functions that partially overlap, 2961*38fd1498Szrj thus take the maximum end_line of functions starting 2962*38fd1498Szrj at LINE_NUM. */ 2963*38fd1498Szrj for (unsigned i = 0; i < fns.size (); i++) 2964*38fd1498Szrj if (fns[i]->end_line > line_start_group) 2965*38fd1498Szrj line_start_group = fns[i]->end_line; 2966*38fd1498Szrj } 2967*38fd1498Szrj else if (fns.size () == 1) 2968*38fd1498Szrj { 2969*38fd1498Szrj function_info *fn = fns[0]; 2970*38fd1498Szrj output_function_details (gcov_file, fn); 2971*38fd1498Szrj } 2972*38fd1498Szrj } 2973*38fd1498Szrj 2974*38fd1498Szrj /* For lines which don't exist in the .bb file, print '-' before 2975*38fd1498Szrj the source line. For lines which exist but were never 2976*38fd1498Szrj executed, print '#####' or '=====' before the source line. 2977*38fd1498Szrj Otherwise, print the execution count before the source line. 2978*38fd1498Szrj There are 16 spaces of indentation added before the source 2979*38fd1498Szrj line so that tabs won't be messed up. */ 2980*38fd1498Szrj output_line_beginning (gcov_file, line->exists, line->unexceptional, 2981*38fd1498Szrj line->has_unexecuted_block, line->count, 2982*38fd1498Szrj line_num, "=====", "#####"); 2983*38fd1498Szrj 2984*38fd1498Szrj print_source_line (gcov_file, source_lines, line_num); 2985*38fd1498Szrj output_line_details (gcov_file, line, line_num); 2986*38fd1498Szrj 2987*38fd1498Szrj if (line_start_group == line_num) 2988*38fd1498Szrj { 2989*38fd1498Szrj for (vector<function_info *>::iterator it = fns.begin (); 2990*38fd1498Szrj it != fns.end (); it++) 2991*38fd1498Szrj { 2992*38fd1498Szrj function_info *fn = *it; 2993*38fd1498Szrj vector<line_info> &lines = fn->lines; 2994*38fd1498Szrj 2995*38fd1498Szrj fprintf (gcov_file, FN_SEPARATOR); 2996*38fd1498Szrj 2997*38fd1498Szrj string fn_name 2998*38fd1498Szrj = flag_demangled_names ? fn->demangled_name : fn->name; 2999*38fd1498Szrj 3000*38fd1498Szrj if (flag_use_colors) 3001*38fd1498Szrj { 3002*38fd1498Szrj fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN)); 3003*38fd1498Szrj fn_name += SGR_RESET; 3004*38fd1498Szrj } 3005*38fd1498Szrj 3006*38fd1498Szrj fprintf (gcov_file, "%s:\n", fn_name.c_str ()); 3007*38fd1498Szrj 3008*38fd1498Szrj output_function_details (gcov_file, fn); 3009*38fd1498Szrj 3010*38fd1498Szrj /* Print all lines covered by the function. */ 3011*38fd1498Szrj for (unsigned i = 0; i < lines.size (); i++) 3012*38fd1498Szrj { 3013*38fd1498Szrj line_info *line = &lines[i]; 3014*38fd1498Szrj unsigned l = fn->start_line + i; 3015*38fd1498Szrj 3016*38fd1498Szrj /* For lines which don't exist in the .bb file, print '-' 3017*38fd1498Szrj before the source line. For lines which exist but 3018*38fd1498Szrj were never executed, print '#####' or '=====' before 3019*38fd1498Szrj the source line. Otherwise, print the execution count 3020*38fd1498Szrj before the source line. 3021*38fd1498Szrj There are 16 spaces of indentation added before the source 3022*38fd1498Szrj line so that tabs won't be messed up. */ 3023*38fd1498Szrj output_line_beginning (gcov_file, line->exists, 3024*38fd1498Szrj line->unexceptional, 3025*38fd1498Szrj line->has_unexecuted_block, 3026*38fd1498Szrj line->count, 3027*38fd1498Szrj l, "=====", "#####"); 3028*38fd1498Szrj 3029*38fd1498Szrj print_source_line (gcov_file, source_lines, l); 3030*38fd1498Szrj output_line_details (gcov_file, line, l); 3031*38fd1498Szrj } 3032*38fd1498Szrj } 3033*38fd1498Szrj 3034*38fd1498Szrj fprintf (gcov_file, FN_SEPARATOR); 3035*38fd1498Szrj line_start_group = 0; 3036*38fd1498Szrj } 3037*38fd1498Szrj } 3038*38fd1498Szrj 3039*38fd1498Szrj if (source_file) 3040*38fd1498Szrj fclose (source_file); 3041*38fd1498Szrj } 3042