comparison gcc/gcov.c @ 132:d34655255c78

update gcc-8.2
author mir3636
date Thu, 25 Oct 2018 10:21:07 +0900
parents 84e7813d76e9
children 1830386684a0
comparison
equal deleted inserted replaced
130:e108057fa461 132:d34655255c78
1 /* Gcov.c: prepend line execution counts and branch probabilities to a 1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file. 2 source file.
3 Copyright (C) 1990-2017 Free Software Foundation, Inc. 3 Copyright (C) 1990-2018 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support. 4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support. 5 Mangled by Bob Manson of Cygnus Support.
6 Mangled further by Nathan Sidwell <nathan@codesourcery.com> 6 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
7 7
8 Gcov is free software; you can redistribute it and/or modify 8 Gcov is free software; you can redistribute it and/or modify
31 probabilities of fall through arcs. */ 31 probabilities of fall through arcs. */
32 32
33 #include "config.h" 33 #include "config.h"
34 #define INCLUDE_ALGORITHM 34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR 35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
37 #define INCLUDE_MAP
38 #define INCLUDE_SET
36 #include "system.h" 39 #include "system.h"
37 #include "coretypes.h" 40 #include "coretypes.h"
38 #include "tm.h" 41 #include "tm.h"
39 #include "intl.h" 42 #include "intl.h"
40 #include "diagnostic.h" 43 #include "diagnostic.h"
41 #include "version.h" 44 #include "version.h"
42 #include "demangle.h" 45 #include "demangle.h"
46 #include "color-macros.h"
43 47
44 #include <getopt.h> 48 #include <getopt.h>
45 49
46 #include "md5.h" 50 #include "md5.h"
47 51
73 struct block_info; 77 struct block_info;
74 struct source_info; 78 struct source_info;
75 79
76 /* Describes an arc between two basic blocks. */ 80 /* Describes an arc between two basic blocks. */
77 81
78 typedef struct arc_info 82 struct arc_info
79 { 83 {
80 /* source and destination blocks. */ 84 /* source and destination blocks. */
81 struct block_info *src; 85 struct block_info *src;
82 struct block_info *dst; 86 struct block_info *dst;
83 87
104 unsigned int is_unconditional : 1; 108 unsigned int is_unconditional : 1;
105 109
106 /* Loop making arc. */ 110 /* Loop making arc. */
107 unsigned int cycle : 1; 111 unsigned int cycle : 1;
108 112
109 /* Next branch on line. */
110 struct arc_info *line_next;
111
112 /* Links to next arc on src and dst lists. */ 113 /* Links to next arc on src and dst lists. */
113 struct arc_info *succ_next; 114 struct arc_info *succ_next;
114 struct arc_info *pred_next; 115 struct arc_info *pred_next;
115 } arc_t; 116 };
116 117
117 /* Describes which locations (lines and files) are associated with 118 /* Describes which locations (lines and files) are associated with
118 a basic block. */ 119 a basic block. */
119 120
120 struct block_location_info 121 struct block_location_info
128 }; 129 };
129 130
130 /* Describes a basic block. Contains lists of arcs to successor and 131 /* Describes a basic block. Contains lists of arcs to successor and
131 predecessor blocks. */ 132 predecessor blocks. */
132 133
133 typedef struct block_info 134 struct block_info
134 { 135 {
135 /* Constructor. */ 136 /* Constructor. */
136 block_info (); 137 block_info ();
137 138
138 /* Chain of exit and entry arcs. */ 139 /* Chain of exit and entry arcs. */
139 arc_t *succ; 140 arc_info *succ;
140 arc_t *pred; 141 arc_info *pred;
141 142
142 /* Number of unprocessed exit and entry arcs. */ 143 /* Number of unprocessed exit and entry arcs. */
143 gcov_type num_succ; 144 gcov_type num_succ;
144 gcov_type num_pred; 145 gcov_type num_pred;
145 146
163 164
164 struct 165 struct
165 { 166 {
166 /* Single line graph cycle workspace. Used for all-blocks 167 /* Single line graph cycle workspace. Used for all-blocks
167 mode. */ 168 mode. */
168 arc_t *arc; 169 arc_info *arc;
169 unsigned ident; 170 unsigned ident;
170 } cycle; /* Used in all-blocks mode, after blocks are linked onto 171 } cycle; /* Used in all-blocks mode, after blocks are linked onto
171 lines. */ 172 lines. */
172 173
173 /* Temporary chain for solving graph, and for chaining blocks on one 174 /* Temporary chain for solving graph, and for chaining blocks on one
174 line. */ 175 line. */
175 struct block_info *chain; 176 struct block_info *chain;
176 177
177 } block_t; 178 };
178 179
179 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0), 180 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
180 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0), 181 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
181 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0), 182 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
182 locations (), chain (NULL) 183 locations (), chain (NULL)
183 { 184 {
184 cycle.arc = NULL; 185 cycle.arc = NULL;
185 } 186 }
186 187
188 /* Describes a single line of source. Contains a chain of basic blocks
189 with code on it. */
190
191 struct line_info
192 {
193 /* Default constructor. */
194 line_info ();
195
196 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
197 bool has_block (block_info *needle);
198
199 /* Execution count. */
200 gcov_type count;
201
202 /* Branches from blocks that end on this line. */
203 vector<arc_info *> branches;
204
205 /* blocks which start on this line. Used in all-blocks mode. */
206 vector<block_info *> blocks;
207
208 unsigned exists : 1;
209 unsigned unexceptional : 1;
210 unsigned has_unexecuted_block : 1;
211 };
212
213 line_info::line_info (): count (0), branches (), blocks (), exists (false),
214 unexceptional (0), has_unexecuted_block (0)
215 {
216 }
217
218 bool
219 line_info::has_block (block_info *needle)
220 {
221 return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
222 }
223
187 /* Describes a single function. Contains an array of basic blocks. */ 224 /* Describes a single function. Contains an array of basic blocks. */
188 225
189 typedef struct function_info 226 struct function_info
190 { 227 {
191 function_info (); 228 function_info ();
192 ~function_info (); 229 ~function_info ();
230
231 /* Return true when line N belongs to the function in source file SRC_IDX.
232 The line must be defined in body of the function, can't be inlined. */
233 bool group_line_p (unsigned n, unsigned src_idx);
234
235 /* Function filter based on function_info::artificial variable. */
236
237 static inline bool
238 is_artificial (function_info *fn)
239 {
240 return fn->artificial;
241 }
193 242
194 /* Name of function. */ 243 /* Name of function. */
195 char *name; 244 char *name;
196 char *demangled_name; 245 char *demangled_name;
197 unsigned ident; 246 unsigned ident;
199 unsigned cfg_checksum; 248 unsigned cfg_checksum;
200 249
201 /* The graph contains at least one fake incoming edge. */ 250 /* The graph contains at least one fake incoming edge. */
202 unsigned has_catch : 1; 251 unsigned has_catch : 1;
203 252
253 /* True when the function is artificial and does not exist
254 in a source file. */
255 unsigned artificial : 1;
256
257 /* True when multiple functions start at a line in a source file. */
258 unsigned is_group : 1;
259
204 /* Array of basic blocks. Like in GCC, the entry block is 260 /* Array of basic blocks. Like in GCC, the entry block is
205 at blocks[0] and the exit block is at blocks[1]. */ 261 at blocks[0] and the exit block is at blocks[1]. */
206 #define ENTRY_BLOCK (0) 262 #define ENTRY_BLOCK (0)
207 #define EXIT_BLOCK (1) 263 #define EXIT_BLOCK (1)
208 vector<block_t> blocks; 264 vector<block_info> blocks;
209 unsigned blocks_executed; 265 unsigned blocks_executed;
210 266
211 /* Raw arc coverage counts. */ 267 /* Raw arc coverage counts. */
212 gcov_type *counts; 268 vector<gcov_type> counts;
213 unsigned num_counts; 269
214 270 /* First line number. */
215 /* First line number & file. */ 271 unsigned start_line;
216 unsigned line; 272
273 /* First line column. */
274 unsigned start_column;
275
276 /* Last line number. */
277 unsigned end_line;
278
279 /* Index of source file where the function is defined. */
217 unsigned src; 280 unsigned src;
218 281
219 /* Next function in same source file. */ 282 /* Vector of line information. */
220 struct function_info *next_file_fn; 283 vector<line_info> lines;
221 284
222 /* Next function. */ 285 /* Next function. */
223 struct function_info *next; 286 struct function_info *next;
224 } function_t; 287 };
288
289 /* Function info comparer that will sort functions according to starting
290 line. */
291
292 struct function_line_start_cmp
293 {
294 inline bool operator() (const function_info *lhs,
295 const function_info *rhs)
296 {
297 return (lhs->start_line == rhs->start_line
298 ? lhs->start_column < rhs->start_column
299 : lhs->start_line < rhs->start_line);
300 }
301 };
225 302
226 /* Describes coverage of a file or function. */ 303 /* Describes coverage of a file or function. */
227 304
228 typedef struct coverage_info 305 struct coverage_info
229 { 306 {
230 int lines; 307 int lines;
231 int lines_executed; 308 int lines_executed;
232 309
233 int branches; 310 int branches;
236 313
237 int calls; 314 int calls;
238 int calls_executed; 315 int calls_executed;
239 316
240 char *name; 317 char *name;
241 } coverage_t; 318 };
242
243 /* Describes a single line of source. Contains a chain of basic blocks
244 with code on it. */
245
246 typedef struct line_info
247 {
248 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
249 bool has_block (block_t *needle);
250
251 gcov_type count; /* execution count */
252 arc_t *branches; /* branches from blocks that end on this line. */
253 block_t *blocks; /* blocks which start on this line.
254 Used in all-blocks mode. */
255 unsigned exists : 1;
256 unsigned unexceptional : 1;
257 } line_t;
258
259 bool
260 line_t::has_block (block_t *needle)
261 {
262 for (block_t *n = blocks; n; n = n->chain)
263 if (n == needle)
264 return true;
265
266 return false;
267 }
268 319
269 /* Describes a file mentioned in the block graph. Contains an array 320 /* Describes a file mentioned in the block graph. Contains an array
270 of line info. */ 321 of line info. */
271 322
272 typedef struct source_info 323 struct source_info
273 { 324 {
325 /* Default constructor. */
326 source_info ();
327
328 vector<function_info *> get_functions_at_location (unsigned line_num) const;
329
330 /* Index of the source_info in sources vector. */
331 unsigned index;
332
274 /* Canonical name of source file. */ 333 /* Canonical name of source file. */
275 char *name; 334 char *name;
276 time_t file_time; 335 time_t file_time;
277 336
278 /* Array of line information. */ 337 /* Vector of line information. */
279 line_t *lines; 338 vector<line_info> lines;
280 unsigned num_lines; 339
281 340 coverage_info coverage;
282 coverage_t coverage; 341
342 /* Maximum line count in the source file. */
343 unsigned int maximum_count;
283 344
284 /* Functions in this source file. These are in ascending line 345 /* Functions in this source file. These are in ascending line
285 number order. */ 346 number order. */
286 function_t *functions; 347 vector <function_info *> functions;
287 } source_t; 348 };
288 349
289 typedef struct name_map 350 source_info::source_info (): index (0), name (NULL), file_time (),
290 { 351 lines (), coverage (), maximum_count (0), functions ()
291 char *name; /* Source file name */ 352 {
353 }
354
355 vector<function_info *>
356 source_info::get_functions_at_location (unsigned line_num) const
357 {
358 vector<function_info *> r;
359
360 for (vector<function_info *>::const_iterator it = functions.begin ();
361 it != functions.end (); it++)
362 {
363 if ((*it)->start_line == line_num && (*it)->src == index)
364 r.push_back (*it);
365 }
366
367 std::sort (r.begin (), r.end (), function_line_start_cmp ());
368
369 return r;
370 }
371
372 class name_map
373 {
374 public:
375 name_map ()
376 {
377 }
378
379 name_map (char *_name, unsigned _src): name (_name), src (_src)
380 {
381 }
382
383 bool operator== (const name_map &rhs) const
384 {
385 #if HAVE_DOS_BASED_FILE_SYSTEM
386 return strcasecmp (this->name, rhs.name) == 0;
387 #else
388 return strcmp (this->name, rhs.name) == 0;
389 #endif
390 }
391
392 bool operator< (const name_map &rhs) const
393 {
394 #if HAVE_DOS_BASED_FILE_SYSTEM
395 return strcasecmp (this->name, rhs.name) < 0;
396 #else
397 return strcmp (this->name, rhs.name) < 0;
398 #endif
399 }
400
401 const char *name; /* Source file name */
292 unsigned src; /* Source file */ 402 unsigned src; /* Source file */
293 } name_map_t; 403 };
294 404
295 /* Holds a list of function basic block graphs. */ 405 /* Vector of all functions. */
296 406 static vector<function_info *> functions;
297 static function_t *functions; 407
298 static function_t **fn_end = &functions; 408 /* Vector of source files. */
299 409 static vector<source_info> sources;
300 static source_t *sources; /* Array of source files */ 410
301 static unsigned n_sources; /* Number of sources */ 411 /* Mapping of file names to sources */
302 static unsigned a_sources; /* Allocated sources */ 412 static vector<name_map> names;
303 413
304 static name_map_t *names; /* Mapping of file names to sources */ 414 /* Record all processed files in order to warn about
305 static unsigned n_names; /* Number of names */ 415 a file being read multiple times. */
306 static unsigned a_names; /* Allocated names */ 416 static vector<char *> processed_files;
307 417
308 /* This holds data summary information. */ 418 /* This holds data summary information. */
309 419
310 static unsigned object_runs; 420 static unsigned object_runs;
311 static unsigned program_count;
312 421
313 static unsigned total_lines; 422 static unsigned total_lines;
314 static unsigned total_executed; 423 static unsigned total_executed;
315 424
316 /* Modification time of graph file. */ 425 /* Modification time of graph file. */
323 432
324 static char *bbg_file_name; 433 static char *bbg_file_name;
325 434
326 /* Stamp of the bbg file */ 435 /* Stamp of the bbg file */
327 static unsigned bbg_stamp; 436 static unsigned bbg_stamp;
437
438 /* Supports has_unexecuted_blocks functionality. */
439 static unsigned bbg_supports_has_unexecuted_blocks;
440
441 /* Working directory in which a TU was compiled. */
442 static const char *bbg_cwd;
328 443
329 /* Name and file pointer of the input file for the count data (gcda). */ 444 /* Name and file pointer of the input file for the count data (gcda). */
330 445
331 static char *da_file_name; 446 static char *da_file_name;
332 447
351 /* Output a gcov file if this is true. This is on by default, and can 466 /* Output a gcov file if this is true. This is on by default, and can
352 be turned off by the -n option. */ 467 be turned off by the -n option. */
353 468
354 static int flag_gcov_file = 1; 469 static int flag_gcov_file = 1;
355 470
471 /* Output to stdout instead to a gcov file. */
472
473 static int flag_use_stdout = 0;
474
356 /* Output progress indication if this is true. This is off by default 475 /* Output progress indication if this is true. This is off by default
357 and can be turned on by the -d option. */ 476 and can be turned on by the -d option. */
358 477
359 static int flag_display_progress = 0; 478 static int flag_display_progress = 0;
360 479
379 498
380 /* Print verbose informations. */ 499 /* Print verbose informations. */
381 500
382 static int flag_verbose = 0; 501 static int flag_verbose = 0;
383 502
503 /* Print colored output. */
504
505 static int flag_use_colors = 0;
506
507 /* Use perf-like colors to indicate hot lines. */
508
509 static int flag_use_hotness_colors = 0;
510
384 /* Output count information for every basic block, not merely those 511 /* Output count information for every basic block, not merely those
385 that contain line number information. */ 512 that contain line number information. */
386 513
387 static int flag_all_blocks = 0; 514 static int flag_all_blocks = 0;
515
516 /* Output human readable numbers. */
517
518 static int flag_human_readable_numbers = 0;
388 519
389 /* Output summary info for each function. */ 520 /* Output summary info for each function. */
390 521
391 static int flag_function_summary = 0; 522 static int flag_function_summary = 0;
392 523
420 /* Forward declarations. */ 551 /* Forward declarations. */
421 static int process_args (int, char **); 552 static int process_args (int, char **);
422 static void print_usage (int) ATTRIBUTE_NORETURN; 553 static void print_usage (int) ATTRIBUTE_NORETURN;
423 static void print_version (void) ATTRIBUTE_NORETURN; 554 static void print_version (void) ATTRIBUTE_NORETURN;
424 static void process_file (const char *); 555 static void process_file (const char *);
556 static void process_all_functions (void);
425 static void generate_results (const char *); 557 static void generate_results (const char *);
426 static void create_file_names (const char *); 558 static void create_file_names (const char *);
427 static int name_search (const void *, const void *);
428 static int name_sort (const void *, const void *);
429 static char *canonicalize_name (const char *); 559 static char *canonicalize_name (const char *);
430 static unsigned find_source (const char *); 560 static unsigned find_source (const char *);
431 static function_t *read_graph_file (void); 561 static void read_graph_file (void);
432 static int read_count_file (function_t *); 562 static int read_count_file (void);
433 static void solve_flow_graph (function_t *); 563 static void solve_flow_graph (function_info *);
434 static void find_exception_blocks (function_t *); 564 static void find_exception_blocks (function_info *);
435 static void add_branch_counts (coverage_t *, const arc_t *); 565 static void add_branch_counts (coverage_info *, const arc_info *);
436 static void add_line_counts (coverage_t *, function_t *); 566 static void add_line_counts (coverage_info *, function_info *);
437 static void executed_summary (unsigned, unsigned); 567 static void executed_summary (unsigned, unsigned);
438 static void function_summary (const coverage_t *, const char *); 568 static void function_summary (const coverage_info *, const char *);
439 static const char *format_gcov (gcov_type, gcov_type, int); 569 static const char *format_gcov (gcov_type, gcov_type, int);
440 static void accumulate_line_counts (source_t *); 570 static void accumulate_line_counts (source_info *);
441 static void output_gcov_file (const char *, source_t *); 571 static void output_gcov_file (const char *, source_info *);
442 static int output_branch_count (FILE *, int, const arc_t *); 572 static int output_branch_count (FILE *, int, const arc_info *);
443 static void output_lines (FILE *, const source_t *); 573 static void output_lines (FILE *, const source_info *);
444 static char *make_gcov_file_name (const char *, const char *); 574 static char *make_gcov_file_name (const char *, const char *);
445 static char *mangle_name (const char *, char *); 575 static char *mangle_name (const char *, char *);
446 static void release_structures (void); 576 static void release_structures (void);
447 extern int main (int, char **); 577 extern int main (int, char **);
448 578
449 function_info::function_info (): name (NULL), demangled_name (NULL), 579 function_info::function_info (): name (NULL), demangled_name (NULL),
450 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0), 580 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
451 blocks (), blocks_executed (0), counts (NULL), num_counts (0), 581 artificial (0), is_group (0),
452 line (0), src (0), next_file_fn (NULL), next (NULL) 582 blocks (), blocks_executed (0), counts (),
583 start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL)
453 { 584 {
454 } 585 }
455 586
456 function_info::~function_info () 587 function_info::~function_info ()
457 { 588 {
458 for (int i = blocks.size () - 1; i >= 0; i--) 589 for (int i = blocks.size () - 1; i >= 0; i--)
459 { 590 {
460 arc_t *arc, *arc_n; 591 arc_info *arc, *arc_n;
461 592
462 for (arc = blocks[i].succ; arc; arc = arc_n) 593 for (arc = blocks[i].succ; arc; arc = arc_n)
463 { 594 {
464 arc_n = arc->succ_next; 595 arc_n = arc->succ_next;
465 free (arc); 596 free (arc);
466 } 597 }
467 } 598 }
468 free (counts);
469 if (flag_demangled_names && demangled_name != name) 599 if (flag_demangled_names && demangled_name != name)
470 free (demangled_name); 600 free (demangled_name);
471 free (name); 601 free (name);
602 }
603
604 bool function_info::group_line_p (unsigned n, unsigned src_idx)
605 {
606 return is_group && src == src_idx && start_line <= n && n <= end_line;
472 } 607 }
473 608
474 /* Cycle detection! 609 /* Cycle detection!
475 There are a bajillion algorithms that do this. Boost's function is named 610 There are a bajillion algorithms that do this. Boost's function is named
476 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in 611 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
481 in a subgraph (that shrinks every iteration). Duplicates are filtered by 616 in a subgraph (that shrinks every iteration). Duplicates are filtered by
482 "blocking" a path when a node is added to the path (this also prevents non- 617 "blocking" a path when a node is added to the path (this also prevents non-
483 simple paths)--the node is unblocked only when it participates in a cycle. 618 simple paths)--the node is unblocked only when it participates in a cycle.
484 */ 619 */
485 620
486 typedef vector<arc_t *> arc_vector_t; 621 typedef vector<arc_info *> arc_vector_t;
487 typedef vector<const block_t *> block_vector_t; 622 typedef vector<const block_info *> block_vector_t;
488 623
489 /* Enum with types of loop in CFG. */ 624 /* Enum with types of loop in CFG. */
490 625
491 enum loop_type 626 enum loop_type
492 { 627 {
527 662
528 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks 663 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
529 blocked by U in BLOCK_LISTS. */ 664 blocked by U in BLOCK_LISTS. */
530 665
531 static void 666 static void
532 unblock (const block_t *u, block_vector_t &blocked, 667 unblock (const block_info *u, block_vector_t &blocked,
533 vector<block_vector_t > &block_lists) 668 vector<block_vector_t > &block_lists)
534 { 669 {
535 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u); 670 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
536 if (it == blocked.end ()) 671 if (it == blocked.end ())
537 return; 672 return;
552 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices 687 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
553 blocked by a block. COUNT is accumulated count of the current LINE. 688 blocked by a block. COUNT is accumulated count of the current LINE.
554 Returns what type of loop it contains. */ 689 Returns what type of loop it contains. */
555 690
556 static loop_type 691 static loop_type
557 circuit (block_t *v, arc_vector_t &path, block_t *start, 692 circuit (block_info *v, arc_vector_t &path, block_info *start,
558 block_vector_t &blocked, vector<block_vector_t> &block_lists, 693 block_vector_t &blocked, vector<block_vector_t> &block_lists,
559 line_t &linfo, int64_t &count) 694 line_info &linfo, int64_t &count)
560 { 695 {
561 loop_type result = NO_LOOP; 696 loop_type result = NO_LOOP;
562 697
563 /* Add v to the block list. */ 698 /* Add v to the block list. */
564 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ()); 699 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
565 blocked.push_back (v); 700 blocked.push_back (v);
566 block_lists.push_back (block_vector_t ()); 701 block_lists.push_back (block_vector_t ());
567 702
568 for (arc_t *arc = v->succ; arc; arc = arc->succ_next) 703 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
569 { 704 {
570 block_t *w = arc->dst; 705 block_info *w = arc->dst;
571 if (w < start || !linfo.has_block (w)) 706 if (w < start || !linfo.has_block (w))
572 continue; 707 continue;
573 708
574 path.push_back (arc); 709 path.push_back (arc);
575 if (w == start) 710 if (w == start)
582 } 717 }
583 718
584 if (result != NO_LOOP) 719 if (result != NO_LOOP)
585 unblock (v, blocked, block_lists); 720 unblock (v, blocked, block_lists);
586 else 721 else
587 for (arc_t *arc = v->succ; arc; arc = arc->succ_next) 722 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
588 { 723 {
589 block_t *w = arc->dst; 724 block_info *w = arc->dst;
590 if (w < start || !linfo.has_block (w)) 725 if (w < start || !linfo.has_block (w))
591 continue; 726 continue;
592 727
593 size_t index 728 size_t index
594 = find (blocked.begin (), blocked.end (), w) - blocked.begin (); 729 = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
603 738
604 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line 739 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
605 contains a negative loop, then perform the same function once again. */ 740 contains a negative loop, then perform the same function once again. */
606 741
607 static gcov_type 742 static gcov_type
608 get_cycles_count (line_t &linfo, bool handle_negative_cycles = true) 743 get_cycles_count (line_info &linfo, bool handle_negative_cycles = true)
609 { 744 {
610 /* Note that this algorithm works even if blocks aren't in sorted order. 745 /* Note that this algorithm works even if blocks aren't in sorted order.
611 Each iteration of the circuit detection is completely independent 746 Each iteration of the circuit detection is completely independent
612 (except for reducing counts, but that shouldn't matter anyways). 747 (except for reducing counts, but that shouldn't matter anyways).
613 Therefore, operating on a permuted order (i.e., non-sorted) only 748 Therefore, operating on a permuted order (i.e., non-sorted) only
614 has the effect of permuting the output cycles. */ 749 has the effect of permuting the output cycles. */
615 750
616 loop_type result = NO_LOOP; 751 loop_type result = NO_LOOP;
617 gcov_type count = 0; 752 gcov_type count = 0;
618 for (block_t *block = linfo.blocks; block; block = block->chain) 753 for (vector<block_info *>::iterator it = linfo.blocks.begin ();
754 it != linfo.blocks.end (); it++)
619 { 755 {
620 arc_vector_t path; 756 arc_vector_t path;
621 block_vector_t blocked; 757 block_vector_t blocked;
622 vector<block_vector_t > block_lists; 758 vector<block_vector_t > block_lists;
623 result |= circuit (block, path, block, blocked, block_lists, linfo, 759 result |= circuit (*it, path, *it, blocked, block_lists, linfo,
624 count); 760 count);
625 } 761 }
626 762
627 /* If we have a negative cycle, repeat the find_cycles routine. */ 763 /* If we have a negative cycle, repeat the find_cycles routine. */
628 if (result == NEGATIVE_LOOP && handle_negative_cycles) 764 if (result == NEGATIVE_LOOP && handle_negative_cycles)
653 diagnostic_initialize (global_dc, 0); 789 diagnostic_initialize (global_dc, 0);
654 790
655 /* Handle response files. */ 791 /* Handle response files. */
656 expandargv (&argc, &argv); 792 expandargv (&argc, &argv);
657 793
658 a_names = 10;
659 names = XNEWVEC (name_map_t, a_names);
660 a_sources = 10;
661 sources = XNEWVEC (source_t, a_sources);
662
663 argno = process_args (argc, argv); 794 argno = process_args (argc, argv);
664 if (optind == argc) 795 if (optind == argc)
665 print_usage (true); 796 print_usage (true);
666 797
667 if (argc - argno > 1) 798 if (argc - argno > 1)
673 { 804 {
674 if (flag_display_progress) 805 if (flag_display_progress)
675 printf ("Processing file %d out of %d\n", argno - first_arg + 1, 806 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
676 argc - first_arg); 807 argc - first_arg);
677 process_file (argv[argno]); 808 process_file (argv[argno]);
678 } 809
679 810 if (flag_intermediate_format || argno == argc - 1)
680 generate_results (multiple_files ? NULL : argv[argc - 1]); 811 {
681 812 process_all_functions ();
682 release_structures (); 813 generate_results (argv[argno]);
814 release_structures ();
815 }
816 }
683 817
684 return 0; 818 return 0;
685 } 819 }
686 820
687 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, 821 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
701 rather than percentages\n"); 835 rather than percentages\n");
702 fnotice (file, " -d, --display-progress Display progress information\n"); 836 fnotice (file, " -d, --display-progress Display progress information\n");
703 fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 837 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
704 fnotice (file, " -h, --help Print this help, then exit\n"); 838 fnotice (file, " -h, --help Print this help, then exit\n");
705 fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n"); 839 fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
840 fnotice (file, " -j, --human-readable Output human readable numbers\n");
841 fnotice (file, " -k, --use-colors Emit colored output\n");
706 fnotice (file, " -l, --long-file-names Use long output file names for included\n\ 842 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
707 source files\n"); 843 source files\n");
708 fnotice (file, " -m, --demangled-names Output demangled function names\n"); 844 fnotice (file, " -m, --demangled-names Output demangled function names\n");
709 fnotice (file, " -n, --no-output Do not create an output file\n"); 845 fnotice (file, " -n, --no-output Do not create an output file\n");
710 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); 846 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
711 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); 847 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
848 fnotice (file, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
712 fnotice (file, " -r, --relative-only Only show data for relative sources\n"); 849 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
713 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n"); 850 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
851 fnotice (file, " -t, --stdout Output to stdout instead of a file\n");
714 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); 852 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
715 fnotice (file, " -v, --version Print version number, then exit\n"); 853 fnotice (file, " -v, --version Print version number, then exit\n");
716 fnotice (file, " -w, --verbose Print verbose informations\n"); 854 fnotice (file, " -w, --verbose Print verbose informations\n");
717 fnotice (file, " -x, --hash-filenames Hash long pathnames\n"); 855 fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
718 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", 856 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
724 862
725 static void 863 static void
726 print_version (void) 864 print_version (void)
727 { 865 {
728 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string); 866 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
729 fprintf (stdout, "Copyright %s 2017 Free Software Foundation, Inc.\n", 867 fprintf (stdout, "Copyright %s 2018 Free Software Foundation, Inc.\n",
730 _("(C)")); 868 _("(C)"));
731 fnotice (stdout, 869 fnotice (stdout,
732 _("This is free software; see the source for copying conditions.\n" 870 _("This is free software; see the source for copying conditions.\n"
733 "There is NO warranty; not even for MERCHANTABILITY or \n" 871 "There is NO warranty; not even for MERCHANTABILITY or \n"
734 "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 872 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
742 { "verbose", no_argument, NULL, 'w' }, 880 { "verbose", no_argument, NULL, 'w' },
743 { "all-blocks", no_argument, NULL, 'a' }, 881 { "all-blocks", no_argument, NULL, 'a' },
744 { "branch-probabilities", no_argument, NULL, 'b' }, 882 { "branch-probabilities", no_argument, NULL, 'b' },
745 { "branch-counts", no_argument, NULL, 'c' }, 883 { "branch-counts", no_argument, NULL, 'c' },
746 { "intermediate-format", no_argument, NULL, 'i' }, 884 { "intermediate-format", no_argument, NULL, 'i' },
885 { "human-readable", no_argument, NULL, 'j' },
747 { "no-output", no_argument, NULL, 'n' }, 886 { "no-output", no_argument, NULL, 'n' },
748 { "long-file-names", no_argument, NULL, 'l' }, 887 { "long-file-names", no_argument, NULL, 'l' },
749 { "function-summaries", no_argument, NULL, 'f' }, 888 { "function-summaries", no_argument, NULL, 'f' },
750 { "demangled-names", no_argument, NULL, 'm' }, 889 { "demangled-names", no_argument, NULL, 'm' },
751 { "preserve-paths", no_argument, NULL, 'p' }, 890 { "preserve-paths", no_argument, NULL, 'p' },
752 { "relative-only", no_argument, NULL, 'r' }, 891 { "relative-only", no_argument, NULL, 'r' },
753 { "object-directory", required_argument, NULL, 'o' }, 892 { "object-directory", required_argument, NULL, 'o' },
754 { "object-file", required_argument, NULL, 'o' }, 893 { "object-file", required_argument, NULL, 'o' },
755 { "source-prefix", required_argument, NULL, 's' }, 894 { "source-prefix", required_argument, NULL, 's' },
895 { "stdout", no_argument, NULL, 't' },
756 { "unconditional-branches", no_argument, NULL, 'u' }, 896 { "unconditional-branches", no_argument, NULL, 'u' },
757 { "display-progress", no_argument, NULL, 'd' }, 897 { "display-progress", no_argument, NULL, 'd' },
758 { "hash-filenames", no_argument, NULL, 'x' }, 898 { "hash-filenames", no_argument, NULL, 'x' },
899 { "use-colors", no_argument, NULL, 'k' },
900 { "use-hotness-colors", no_argument, NULL, 'q' },
759 { 0, 0, 0, 0 } 901 { 0, 0, 0, 0 }
760 }; 902 };
761 903
762 /* Process args, return index to first non-arg. */ 904 /* Process args, return index to first non-arg. */
763 905
764 static int 906 static int
765 process_args (int argc, char **argv) 907 process_args (int argc, char **argv)
766 { 908 {
767 int opt; 909 int opt;
768 910
769 const char *opts = "abcdfhilmno:prs:uvwx"; 911 const char *opts = "abcdfhijklmno:pqrs:tuvwx";
770 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1) 912 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
771 { 913 {
772 switch (opt) 914 switch (opt)
773 { 915 {
774 case 'a': 916 case 'a':
786 case 'h': 928 case 'h':
787 print_usage (false); 929 print_usage (false);
788 /* print_usage will exit. */ 930 /* print_usage will exit. */
789 case 'l': 931 case 'l':
790 flag_long_names = 1; 932 flag_long_names = 1;
933 break;
934 case 'j':
935 flag_human_readable_numbers = 1;
936 break;
937 case 'k':
938 flag_use_colors = 1;
939 break;
940 case 'q':
941 flag_use_hotness_colors = 1;
791 break; 942 break;
792 case 'm': 943 case 'm':
793 flag_demangled_names = 1; 944 flag_demangled_names = 1;
794 break; 945 break;
795 case 'n': 946 case 'n':
822 flag_hash_filenames = 1; 973 flag_hash_filenames = 1;
823 break; 974 break;
824 case 'w': 975 case 'w':
825 flag_verbose = 1; 976 flag_verbose = 1;
826 break; 977 break;
978 case 't':
979 flag_use_stdout = 1;
980 break;
827 case 'v': 981 case 'v':
828 print_version (); 982 print_version ();
829 /* print_version will exit. */ 983 /* print_version will exit. */
830 default: 984 default:
831 print_usage (true); 985 print_usage (true);
834 } 988 }
835 989
836 return optind; 990 return optind;
837 } 991 }
838 992
993 /* Output intermediate LINE sitting on LINE_NUM to output file F. */
994
995 static void
996 output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
997 {
998 if (!line->exists)
999 return;
1000
1001 fprintf (f, "lcount:%u,%s,%d\n", line_num,
1002 format_gcov (line->count, 0, -1),
1003 line->has_unexecuted_block);
1004
1005 vector<arc_info *>::const_iterator it;
1006 if (flag_branches)
1007 for (it = line->branches.begin (); it != line->branches.end ();
1008 it++)
1009 {
1010 if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1011 {
1012 const char *branch_type;
1013 /* branch:<line_num>,<branch_coverage_infoype>
1014 branch_coverage_infoype
1015 : notexec (Branch not executed)
1016 : taken (Branch executed and taken)
1017 : nottaken (Branch executed, but not taken)
1018 */
1019 if ((*it)->src->count)
1020 branch_type
1021 = ((*it)->count > 0) ? "taken" : "nottaken";
1022 else
1023 branch_type = "notexec";
1024 fprintf (f, "branch:%d,%s\n", line_num, branch_type);
1025 }
1026 }
1027 }
1028
1029 /* Get the name of the gcov file. The return value must be free'd.
1030
1031 It appends the '.gcov' extension to the *basename* of the file.
1032 The resulting file name will be in PWD.
1033
1034 e.g.,
1035 input: foo.da, output: foo.da.gcov
1036 input: a/b/foo.cc, output: foo.cc.gcov */
1037
1038 static char *
1039 get_gcov_intermediate_filename (const char *file_name)
1040 {
1041 const char *gcov = ".gcov";
1042 char *result;
1043 const char *cptr;
1044
1045 /* Find the 'basename'. */
1046 cptr = lbasename (file_name);
1047
1048 result = XNEWVEC (char, strlen (cptr) + strlen (gcov) + 1);
1049 sprintf (result, "%s%s", cptr, gcov);
1050
1051 return result;
1052 }
1053
839 /* Output the result in intermediate format used by 'lcov'. 1054 /* Output the result in intermediate format used by 'lcov'.
840 1055
841 The intermediate format contains a single file named 'foo.cc.gcov', 1056 The intermediate format contains a single file named 'foo.cc.gcov',
842 with no source code included. A sample output is 1057 with no source code included.
843
844 file:foo.cc
845 function:5,1,_Z3foov
846 function:13,1,main
847 function:19,1,_GLOBAL__sub_I__Z3foov
848 function:19,1,_Z41__static_initialization_and_destruction_0ii
849 lcount:5,1
850 lcount:7,9
851 lcount:9,8
852 lcount:11,1
853 file:/.../iostream
854 lcount:74,1
855 file:/.../basic_ios.h
856 file:/.../ostream
857 file:/.../ios_base.h
858 function:157,0,_ZStorSt12_Ios_IostateS_
859 lcount:157,0
860 file:/.../char_traits.h
861 function:258,0,_ZNSt11char_traitsIcE6lengthEPKc
862 lcount:258,0
863 ...
864 1058
865 The default gcov outputs multiple files: 'foo.cc.gcov', 1059 The default gcov outputs multiple files: 'foo.cc.gcov',
866 'iostream.gcov', 'ios_base.h.gcov', etc. with source code 1060 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
867 included. Instead the intermediate format here outputs only a single 1061 included. Instead the intermediate format here outputs only a single
868 file 'foo.cc.gcov' similar to the above example. */ 1062 file 'foo.cc.gcov' similar to the above example. */
869 1063
870 static void 1064 static void
871 output_intermediate_file (FILE *gcov_file, source_t *src) 1065 output_intermediate_file (FILE *gcov_file, source_info *src)
872 { 1066 {
873 unsigned line_num; /* current line number. */ 1067 fprintf (gcov_file, "version:%s\n", version_string);
874 const line_t *line; /* current line info ptr. */
875 function_t *fn; /* current function info ptr. */
876
877 fprintf (gcov_file, "file:%s\n", src->name); /* source file name */ 1068 fprintf (gcov_file, "file:%s\n", src->name); /* source file name */
878 1069 fprintf (gcov_file, "cwd:%s\n", bbg_cwd);
879 for (fn = src->functions; fn; fn = fn->next_file_fn) 1070
1071 std::sort (src->functions.begin (), src->functions.end (),
1072 function_line_start_cmp ());
1073 for (vector<function_info *>::iterator it = src->functions.begin ();
1074 it != src->functions.end (); it++)
880 { 1075 {
881 /* function:<name>,<line_number>,<execution_count> */ 1076 /* function:<name>,<line_number>,<execution_count> */
882 fprintf (gcov_file, "function:%d,%s,%s\n", fn->line, 1077 fprintf (gcov_file, "function:%d,%d,%s,%s\n", (*it)->start_line,
883 format_gcov (fn->blocks[0].count, 0, -1), 1078 (*it)->end_line, format_gcov ((*it)->blocks[0].count, 0, -1),
884 flag_demangled_names ? fn->demangled_name : fn->name); 1079 flag_demangled_names ? (*it)->demangled_name : (*it)->name);
885 } 1080 }
886 1081
887 for (line_num = 1, line = &src->lines[line_num]; 1082 for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
888 line_num < src->num_lines; 1083 {
889 line_num++, line++) 1084 vector<function_info *> fns = src->get_functions_at_location (line_num);
890 { 1085
891 arc_t *arc; 1086 /* Print first group functions that begin on the line. */
892 if (line->exists) 1087 for (vector<function_info *>::iterator it2 = fns.begin ();
893 fprintf (gcov_file, "lcount:%u,%s\n", line_num, 1088 it2 != fns.end (); it2++)
894 format_gcov (line->count, 0, -1)); 1089 {
895 if (flag_branches) 1090 vector<line_info> &lines = (*it2)->lines;
896 for (arc = line->branches; arc; arc = arc->line_next) 1091 for (unsigned i = 0; i < lines.size (); i++)
897 { 1092 {
898 if (!arc->is_unconditional && !arc->is_call_non_return) 1093 line_info *line = &lines[i];
899 { 1094 output_intermediate_line (gcov_file, line, line_num + i);
900 const char *branch_type; 1095 }
901 /* branch:<line_num>,<branch_coverage_type> 1096 }
902 branch_coverage_type 1097
903 : notexec (Branch not executed) 1098 /* Follow with lines associated with the source file. */
904 : taken (Branch executed and taken) 1099 if (line_num < src->lines.size ())
905 : nottaken (Branch executed, but not taken) 1100 output_intermediate_line (gcov_file, &src->lines[line_num], line_num);
906 */ 1101 }
907 if (arc->src->count) 1102 }
908 branch_type = (arc->count > 0) ? "taken" : "nottaken"; 1103
909 else 1104 /* Function start pair. */
910 branch_type = "notexec"; 1105 struct function_start
911 fprintf (gcov_file, "branch:%d,%s\n", line_num, branch_type); 1106 {
912 } 1107 unsigned source_file_idx;
913 } 1108 unsigned start_line;
914 } 1109 };
915 } 1110
1111 /* Traits class for function start hash maps below. */
1112
1113 struct function_start_pair_hash : typed_noop_remove <function_start>
1114 {
1115 typedef function_start value_type;
1116 typedef function_start compare_type;
1117
1118 static hashval_t
1119 hash (const function_start &ref)
1120 {
1121 inchash::hash hstate (0);
1122 hstate.add_int (ref.source_file_idx);
1123 hstate.add_int (ref.start_line);
1124 return hstate.end ();
1125 }
1126
1127 static bool
1128 equal (const function_start &ref1, const function_start &ref2)
1129 {
1130 return (ref1.source_file_idx == ref2.source_file_idx
1131 && ref1.start_line == ref2.start_line);
1132 }
1133
1134 static void
1135 mark_deleted (function_start &ref)
1136 {
1137 ref.start_line = ~1U;
1138 }
1139
1140 static void
1141 mark_empty (function_start &ref)
1142 {
1143 ref.start_line = ~2U;
1144 }
1145
1146 static bool
1147 is_deleted (const function_start &ref)
1148 {
1149 return ref.start_line == ~1U;
1150 }
1151
1152 static bool
1153 is_empty (const function_start &ref)
1154 {
1155 return ref.start_line == ~2U;
1156 }
1157 };
916 1158
917 /* Process a single input file. */ 1159 /* Process a single input file. */
918 1160
919 static void 1161 static void
920 process_file (const char *file_name) 1162 process_file (const char *file_name)
921 { 1163 {
922 function_t *fns;
923
924 create_file_names (file_name); 1164 create_file_names (file_name);
925 fns = read_graph_file (); 1165
926 if (!fns) 1166 for (unsigned i = 0; i < processed_files.size (); i++)
927 return; 1167 if (strcmp (da_file_name, processed_files[i]) == 0)
928 1168 {
929 read_count_file (fns); 1169 fnotice (stderr, "'%s' file is already processed\n",
930 while (fns) 1170 file_name);
931 { 1171 return;
932 function_t *fn = fns; 1172 }
933 1173
934 fns = fn->next; 1174 processed_files.push_back (xstrdup (da_file_name));
935 fn->next = NULL; 1175
936 if (fn->counts || no_data_file) 1176 read_graph_file ();
937 { 1177 read_count_file ();
938 unsigned src = fn->src; 1178 }
939 unsigned line = fn->line; 1179
940 unsigned block_no; 1180 /* Process all functions in all files. */
941 function_t *probe, **prev; 1181
942 1182 static void
943 /* Now insert it into the source file's list of 1183 process_all_functions (void)
944 functions. Normally functions will be encountered in 1184 {
945 ascending order, so a simple scan is quick. Note we're 1185 hash_map<function_start_pair_hash, function_info *> fn_map;
946 building this list in reverse order. */ 1186
947 for (prev = &sources[src].functions; 1187 /* Identify group functions. */
948 (probe = *prev); prev = &probe->next_file_fn) 1188 for (vector<function_info *>::iterator it = functions.begin ();
949 if (probe->line <= line) 1189 it != functions.end (); it++)
950 break; 1190 if (!(*it)->artificial)
951 fn->next_file_fn = probe; 1191 {
952 *prev = fn; 1192 function_start needle;
1193 needle.source_file_idx = (*it)->src;
1194 needle.start_line = (*it)->start_line;
1195
1196 function_info **slot = fn_map.get (needle);
1197 if (slot)
1198 {
1199 (*slot)->is_group = 1;
1200 (*it)->is_group = 1;
1201 }
1202 else
1203 fn_map.put (needle, *it);
1204 }
1205
1206 /* Remove all artificial function. */
1207 functions.erase (remove_if (functions.begin (), functions.end (),
1208 function_info::is_artificial), functions.end ());
1209
1210 for (vector<function_info *>::iterator it = functions.begin ();
1211 it != functions.end (); it++)
1212 {
1213 function_info *fn = *it;
1214 unsigned src = fn->src;
1215
1216 if (!fn->counts.empty () || no_data_file)
1217 {
1218 source_info *s = &sources[src];
1219 s->functions.push_back (fn);
953 1220
954 /* Mark last line in files touched by function. */ 1221 /* Mark last line in files touched by function. */
955 for (block_no = 0; block_no != fn->blocks.size (); block_no++) 1222 for (unsigned block_no = 0; block_no != fn->blocks.size ();
1223 block_no++)
956 { 1224 {
957 block_t *block = &fn->blocks[block_no]; 1225 block_info *block = &fn->blocks[block_no];
958 for (unsigned i = 0; i < block->locations.size (); i++) 1226 for (unsigned i = 0; i < block->locations.size (); i++)
959 { 1227 {
960 unsigned s = block->locations[i].source_file_idx;
961
962 /* Sort lines of locations. */ 1228 /* Sort lines of locations. */
963 sort (block->locations[i].lines.begin (), 1229 sort (block->locations[i].lines.begin (),
964 block->locations[i].lines.end ()); 1230 block->locations[i].lines.end ());
965 1231
966 if (!block->locations[i].lines.empty ()) 1232 if (!block->locations[i].lines.empty ())
967 { 1233 {
1234 s = &sources[block->locations[i].source_file_idx];
968 unsigned last_line 1235 unsigned last_line
969 = block->locations[i].lines.back () + 1; 1236 = block->locations[i].lines.back ();
970 if (last_line > sources[s].num_lines) 1237
971 sources[s].num_lines = last_line; 1238 /* Record new lines for the function. */
1239 if (last_line >= s->lines.size ())
1240 {
1241 s = &sources[block->locations[i].source_file_idx];
1242 unsigned last_line
1243 = block->locations[i].lines.back ();
1244
1245 /* Record new lines for the function. */
1246 if (last_line >= s->lines.size ())
1247 {
1248 /* Record new lines for a source file. */
1249 s->lines.resize (last_line + 1);
1250 }
1251 }
972 } 1252 }
973 } 1253 }
974 } 1254 }
975 1255
1256 /* Allocate lines for group function, following start_line
1257 and end_line information of the function. */
1258 if (fn->is_group)
1259 fn->lines.resize (fn->end_line - fn->start_line + 1);
1260
976 solve_flow_graph (fn); 1261 solve_flow_graph (fn);
977 if (fn->has_catch) 1262 if (fn->has_catch)
978 find_exception_blocks (fn); 1263 find_exception_blocks (fn);
979 *fn_end = fn;
980 fn_end = &fn->next;
981 } 1264 }
982 else 1265 else
983 /* The function was not in the executable -- some other 1266 {
984 instance must have been selected. */ 1267 /* The function was not in the executable -- some other
985 delete fn; 1268 instance must have been selected. */
1269 }
986 } 1270 }
987 } 1271 }
988 1272
989 static void 1273 static void
990 output_gcov_file (const char *file_name, source_t *src) 1274 output_gcov_file (const char *file_name, source_info *src)
991 { 1275 {
992 char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name); 1276 char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
993 1277
994 if (src->coverage.lines) 1278 if (src->coverage.lines)
995 { 1279 {
996 FILE *gcov_file = fopen (gcov_file_name, "w"); 1280 FILE *gcov_file = fopen (gcov_file_name, "w");
997 if (gcov_file) 1281 if (gcov_file)
998 { 1282 {
999 fnotice (stdout, "Creating '%s'\n", gcov_file_name); 1283 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1000 1284 output_lines (gcov_file, src);
1001 if (flag_intermediate_format) 1285 if (ferror (gcov_file))
1002 output_intermediate_file (gcov_file, src); 1286 fnotice (stderr, "Error writing output file '%s'\n",
1003 else 1287 gcov_file_name);
1004 output_lines (gcov_file, src); 1288 fclose (gcov_file);
1005 if (ferror (gcov_file)) 1289 }
1006 fnotice (stderr, "Error writing output file '%s'\n", gcov_file_name);
1007 fclose (gcov_file);
1008 }
1009 else 1290 else
1010 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name); 1291 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1011 } 1292 }
1012 else 1293 else
1013 { 1294 {
1014 unlink (gcov_file_name); 1295 unlink (gcov_file_name);
1015 fnotice (stdout, "Removing '%s'\n", gcov_file_name); 1296 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1018 } 1299 }
1019 1300
1020 static void 1301 static void
1021 generate_results (const char *file_name) 1302 generate_results (const char *file_name)
1022 { 1303 {
1023 unsigned ix; 1304 FILE *gcov_intermediate_file = NULL;
1024 source_t *src; 1305 char *gcov_intermediate_filename = NULL;
1025 function_t *fn; 1306
1026 1307 for (vector<function_info *>::iterator it = functions.begin ();
1027 for (ix = n_sources, src = sources; ix--; src++) 1308 it != functions.end (); it++)
1028 if (src->num_lines) 1309 {
1029 src->lines = XCNEWVEC (line_t, src->num_lines); 1310 function_info *fn = *it;
1030 1311 coverage_info coverage;
1031 for (fn = functions; fn; fn = fn->next)
1032 {
1033 coverage_t coverage;
1034 1312
1035 memset (&coverage, 0, sizeof (coverage)); 1313 memset (&coverage, 0, sizeof (coverage));
1036 coverage.name = flag_demangled_names ? fn->demangled_name : fn->name; 1314 coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
1037 add_line_counts (flag_function_summary ? &coverage : NULL, fn); 1315 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1038 if (flag_function_summary) 1316 if (flag_function_summary)
1040 function_summary (&coverage, "Function"); 1318 function_summary (&coverage, "Function");
1041 fnotice (stdout, "\n"); 1319 fnotice (stdout, "\n");
1042 } 1320 }
1043 } 1321 }
1044 1322
1323 name_map needle;
1324
1045 if (file_name) 1325 if (file_name)
1046 { 1326 {
1047 name_map_t *name_map = (name_map_t *)bsearch 1327 needle.name = file_name;
1048 (file_name, names, n_names, sizeof (*names), name_search); 1328 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1049 if (name_map) 1329 needle);
1050 file_name = sources[name_map->src].coverage.name; 1330 if (it != names.end ())
1331 file_name = sources[it->src].coverage.name;
1051 else 1332 else
1052 file_name = canonicalize_name (file_name); 1333 file_name = canonicalize_name (file_name);
1053 } 1334 }
1054 1335
1055 for (ix = n_sources, src = sources; ix--; src++) 1336 if (flag_gcov_file && flag_intermediate_format && !flag_use_stdout)
1056 { 1337 {
1338 /* Open the intermediate file. */
1339 gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1340 gcov_intermediate_file = fopen (gcov_intermediate_filename, "w");
1341 if (!gcov_intermediate_file)
1342 {
1343 fnotice (stderr, "Cannot open intermediate output file %s\n",
1344 gcov_intermediate_filename);
1345 return;
1346 }
1347 }
1348
1349 for (vector<source_info>::iterator it = sources.begin ();
1350 it != sources.end (); it++)
1351 {
1352 source_info *src = &(*it);
1057 if (flag_relative_only) 1353 if (flag_relative_only)
1058 { 1354 {
1059 /* Ignore this source, if it is an absolute path (after 1355 /* Ignore this source, if it is an absolute path (after
1060 source prefix removal). */ 1356 source prefix removal). */
1061 char first = src->coverage.name[0]; 1357 char first = src->coverage.name[0];
1067 if (IS_DIR_SEPARATOR (first)) 1363 if (IS_DIR_SEPARATOR (first))
1068 continue; 1364 continue;
1069 } 1365 }
1070 1366
1071 accumulate_line_counts (src); 1367 accumulate_line_counts (src);
1072 function_summary (&src->coverage, "File"); 1368
1369 if (!flag_use_stdout)
1370 function_summary (&src->coverage, "File");
1073 total_lines += src->coverage.lines; 1371 total_lines += src->coverage.lines;
1074 total_executed += src->coverage.lines_executed; 1372 total_executed += src->coverage.lines_executed;
1075 if (flag_gcov_file) 1373 if (flag_gcov_file)
1076 { 1374 {
1077 output_gcov_file (file_name, src); 1375 if (flag_intermediate_format)
1078 fnotice (stdout, "\n"); 1376 /* Output the intermediate format without requiring source
1079 } 1377 files. This outputs a section to a *single* file. */
1378 output_intermediate_file ((flag_use_stdout
1379 ? stdout : gcov_intermediate_file), src);
1380 else
1381 {
1382 if (flag_use_stdout)
1383 {
1384 if (src->coverage.lines)
1385 output_lines (stdout, src);
1386 }
1387 else
1388 {
1389 output_gcov_file (file_name, src);
1390 fnotice (stdout, "\n");
1391 }
1392 }
1393 }
1394 }
1395
1396 if (flag_gcov_file && flag_intermediate_format && !flag_use_stdout)
1397 {
1398 /* Now we've finished writing the intermediate file. */
1399 fclose (gcov_intermediate_file);
1400 XDELETEVEC (gcov_intermediate_filename);
1080 } 1401 }
1081 1402
1082 if (!file_name) 1403 if (!file_name)
1083 executed_summary (total_lines, total_executed); 1404 executed_summary (total_lines, total_executed);
1084 } 1405 }
1086 /* Release all memory used. */ 1407 /* Release all memory used. */
1087 1408
1088 static void 1409 static void
1089 release_structures (void) 1410 release_structures (void)
1090 { 1411 {
1091 unsigned ix; 1412 for (vector<function_info *>::iterator it = functions.begin ();
1092 function_t *fn; 1413 it != functions.end (); it++)
1093 1414 delete (*it);
1094 for (ix = n_sources; ix--;) 1415
1095 free (sources[ix].lines); 1416 sources.resize (0);
1096 free (sources); 1417 names.resize (0);
1097 1418 functions.resize (0);
1098 for (ix = n_names; ix--;)
1099 free (names[ix].name);
1100 free (names);
1101
1102 while ((fn = functions))
1103 {
1104 functions = fn->next;
1105 delete fn;
1106 }
1107 } 1419 }
1108 1420
1109 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY 1421 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1110 is not specified, these are named from FILE_NAME sans extension. If 1422 is not specified, these are named from FILE_NAME sans extension. If
1111 OBJECT_DIRECTORY is specified and is a directory, the files are in that 1423 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1172 1484
1173 free (name); 1485 free (name);
1174 return; 1486 return;
1175 } 1487 }
1176 1488
1177 /* A is a string and B is a pointer to name_map_t. Compare for file
1178 name orderability. */
1179
1180 static int
1181 name_search (const void *a_, const void *b_)
1182 {
1183 const char *a = (const char *)a_;
1184 const name_map_t *b = (const name_map_t *)b_;
1185
1186 #if HAVE_DOS_BASED_FILE_SYSTEM
1187 return strcasecmp (a, b->name);
1188 #else
1189 return strcmp (a, b->name);
1190 #endif
1191 }
1192
1193 /* A and B are a pointer to name_map_t. Compare for file name
1194 orderability. */
1195
1196 static int
1197 name_sort (const void *a_, const void *b_)
1198 {
1199 const name_map_t *a = (const name_map_t *)a_;
1200 return name_search (a->name, b_);
1201 }
1202
1203 /* Find or create a source file structure for FILE_NAME. Copies 1489 /* Find or create a source file structure for FILE_NAME. Copies
1204 FILE_NAME on creation */ 1490 FILE_NAME on creation */
1205 1491
1206 static unsigned 1492 static unsigned
1207 find_source (const char *file_name) 1493 find_source (const char *file_name)
1208 { 1494 {
1209 name_map_t *name_map;
1210 char *canon; 1495 char *canon;
1211 unsigned idx; 1496 unsigned idx;
1212 struct stat status; 1497 struct stat status;
1213 1498
1214 if (!file_name) 1499 if (!file_name)
1215 file_name = "<unknown>"; 1500 file_name = "<unknown>";
1216 name_map = (name_map_t *)bsearch 1501
1217 (file_name, names, n_names, sizeof (*names), name_search); 1502 name_map needle;
1218 if (name_map) 1503 needle.name = file_name;
1219 { 1504
1220 idx = name_map->src; 1505 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1506 needle);
1507 if (it != names.end ())
1508 {
1509 idx = it->src;
1221 goto check_date; 1510 goto check_date;
1222 }
1223
1224 if (n_names + 2 > a_names)
1225 {
1226 /* Extend the name map array -- we'll be inserting one or two
1227 entries. */
1228 a_names *= 2;
1229 name_map = XNEWVEC (name_map_t, a_names);
1230 memcpy (name_map, names, n_names * sizeof (*names));
1231 free (names);
1232 names = name_map;
1233 } 1511 }
1234 1512
1235 /* Not found, try the canonical name. */ 1513 /* Not found, try the canonical name. */
1236 canon = canonicalize_name (file_name); 1514 canon = canonicalize_name (file_name);
1237 name_map = (name_map_t *) bsearch (canon, names, n_names, sizeof (*names), 1515 needle.name = canon;
1238 name_search); 1516 it = std::find (names.begin (), names.end (), needle);
1239 if (!name_map) 1517 if (it == names.end ())
1240 { 1518 {
1241 /* Not found with canonical name, create a new source. */ 1519 /* Not found with canonical name, create a new source. */
1242 source_t *src; 1520 source_info *src;
1243 1521
1244 if (n_sources == a_sources) 1522 idx = sources.size ();
1245 { 1523 needle = name_map (canon, idx);
1246 a_sources *= 2; 1524 names.push_back (needle);
1247 src = XNEWVEC (source_t, a_sources); 1525
1248 memcpy (src, sources, n_sources * sizeof (*sources)); 1526 sources.push_back (source_info ());
1249 free (sources); 1527 src = &sources.back ();
1250 sources = src;
1251 }
1252
1253 idx = n_sources;
1254
1255 name_map = &names[n_names++];
1256 name_map->name = canon;
1257 name_map->src = idx;
1258
1259 src = &sources[n_sources++];
1260 memset (src, 0, sizeof (*src));
1261 src->name = canon; 1528 src->name = canon;
1262 src->coverage.name = src->name; 1529 src->coverage.name = src->name;
1530 src->index = idx;
1263 if (source_length 1531 if (source_length
1264 #if HAVE_DOS_BASED_FILE_SYSTEM 1532 #if HAVE_DOS_BASED_FILE_SYSTEM
1265 /* You lose if separators don't match exactly in the 1533 /* You lose if separators don't match exactly in the
1266 prefix. */ 1534 prefix. */
1267 && !strncasecmp (source_prefix, src->coverage.name, source_length) 1535 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1272 src->coverage.name += source_length + 1; 1540 src->coverage.name += source_length + 1;
1273 if (!stat (src->name, &status)) 1541 if (!stat (src->name, &status))
1274 src->file_time = status.st_mtime; 1542 src->file_time = status.st_mtime;
1275 } 1543 }
1276 else 1544 else
1277 idx = name_map->src; 1545 idx = it->src;
1278 1546
1279 if (name_search (file_name, name_map)) 1547 needle.name = file_name;
1548 if (std::find (names.begin (), names.end (), needle) == names.end ())
1280 { 1549 {
1281 /* Append the non-canonical name. */ 1550 /* Append the non-canonical name. */
1282 name_map = &names[n_names++]; 1551 names.push_back (name_map (xstrdup (file_name), idx));
1283 name_map->name = xstrdup (file_name);
1284 name_map->src = idx;
1285 } 1552 }
1286 1553
1287 /* Resort the name map. */ 1554 /* Resort the name map. */
1288 qsort (names, n_names, sizeof (*names), name_sort); 1555 std::sort (names.begin (), names.end ());
1289 1556
1290 check_date: 1557 check_date:
1291 if (sources[idx].file_time > bbg_file_time) 1558 if (sources[idx].file_time > bbg_file_time)
1292 { 1559 {
1293 static int info_emitted; 1560 static int info_emitted;
1304 } 1571 }
1305 1572
1306 return idx; 1573 return idx;
1307 } 1574 }
1308 1575
1309 /* Read the notes file. Return list of functions read -- in reverse order. */ 1576 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1310 1577
1311 static function_t * 1578 static void
1312 read_graph_file (void) 1579 read_graph_file (void)
1313 { 1580 {
1314 unsigned version; 1581 unsigned version;
1315 unsigned current_tag = 0; 1582 unsigned current_tag = 0;
1316 function_t *fn = NULL;
1317 function_t *fns = NULL;
1318 function_t **fns_end = &fns;
1319 unsigned tag; 1583 unsigned tag;
1320 1584
1321 if (!gcov_open (bbg_file_name, 1)) 1585 if (!gcov_open (bbg_file_name, 1))
1322 { 1586 {
1323 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name); 1587 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1324 return fns; 1588 return;
1325 } 1589 }
1326 bbg_file_time = gcov_time (); 1590 bbg_file_time = gcov_time ();
1327 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) 1591 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1328 { 1592 {
1329 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name); 1593 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1330 gcov_close (); 1594 gcov_close ();
1331 return fns; 1595 return;
1332 } 1596 }
1333 1597
1334 version = gcov_read_unsigned (); 1598 version = gcov_read_unsigned ();
1335 if (version != GCOV_VERSION) 1599 if (version != GCOV_VERSION)
1336 { 1600 {
1341 1605
1342 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n", 1606 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1343 bbg_file_name, v, e); 1607 bbg_file_name, v, e);
1344 } 1608 }
1345 bbg_stamp = gcov_read_unsigned (); 1609 bbg_stamp = gcov_read_unsigned ();
1346 1610 bbg_cwd = xstrdup (gcov_read_string ());
1611 bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1612
1613 function_info *fn = NULL;
1347 while ((tag = gcov_read_unsigned ())) 1614 while ((tag = gcov_read_unsigned ()))
1348 { 1615 {
1349 unsigned length = gcov_read_unsigned (); 1616 unsigned length = gcov_read_unsigned ();
1350 gcov_position_t base = gcov_position (); 1617 gcov_position_t base = gcov_position ();
1351 1618
1352 if (tag == GCOV_TAG_FUNCTION) 1619 if (tag == GCOV_TAG_FUNCTION)
1353 { 1620 {
1354 char *function_name; 1621 char *function_name;
1355 unsigned ident, lineno; 1622 unsigned ident;
1356 unsigned lineno_checksum, cfg_checksum; 1623 unsigned lineno_checksum, cfg_checksum;
1357 1624
1358 ident = gcov_read_unsigned (); 1625 ident = gcov_read_unsigned ();
1359 lineno_checksum = gcov_read_unsigned (); 1626 lineno_checksum = gcov_read_unsigned ();
1360 cfg_checksum = gcov_read_unsigned (); 1627 cfg_checksum = gcov_read_unsigned ();
1361 function_name = xstrdup (gcov_read_string ()); 1628 function_name = xstrdup (gcov_read_string ());
1629 unsigned artificial = gcov_read_unsigned ();
1362 unsigned src_idx = find_source (gcov_read_string ()); 1630 unsigned src_idx = find_source (gcov_read_string ());
1363 lineno = gcov_read_unsigned (); 1631 unsigned start_line = gcov_read_unsigned ();
1364 1632 unsigned start_column = gcov_read_unsigned ();
1365 fn = new function_t; 1633 unsigned end_line = gcov_read_unsigned ();
1634
1635 fn = new function_info ();
1636 functions.push_back (fn);
1366 fn->name = function_name; 1637 fn->name = function_name;
1367 if (flag_demangled_names) 1638 if (flag_demangled_names)
1368 { 1639 {
1369 fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS); 1640 fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1370 if (!fn->demangled_name) 1641 if (!fn->demangled_name)
1372 } 1643 }
1373 fn->ident = ident; 1644 fn->ident = ident;
1374 fn->lineno_checksum = lineno_checksum; 1645 fn->lineno_checksum = lineno_checksum;
1375 fn->cfg_checksum = cfg_checksum; 1646 fn->cfg_checksum = cfg_checksum;
1376 fn->src = src_idx; 1647 fn->src = src_idx;
1377 fn->line = lineno; 1648 fn->start_line = start_line;
1378 1649 fn->start_column = start_column;
1379 fn->next_file_fn = NULL; 1650 fn->end_line = end_line;
1380 fn->next = NULL; 1651 fn->artificial = artificial;
1381 *fns_end = fn; 1652
1382 fns_end = &fn->next;
1383 current_tag = tag; 1653 current_tag = tag;
1384 } 1654 }
1385 else if (fn && tag == GCOV_TAG_BLOCKS) 1655 else if (fn && tag == GCOV_TAG_BLOCKS)
1386 { 1656 {
1387 if (!fn->blocks.empty ()) 1657 if (!fn->blocks.empty ())
1393 else if (fn && tag == GCOV_TAG_ARCS) 1663 else if (fn && tag == GCOV_TAG_ARCS)
1394 { 1664 {
1395 unsigned src = gcov_read_unsigned (); 1665 unsigned src = gcov_read_unsigned ();
1396 fn->blocks[src].id = src; 1666 fn->blocks[src].id = src;
1397 unsigned num_dests = GCOV_TAG_ARCS_NUM (length); 1667 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1398 block_t *src_blk = &fn->blocks[src]; 1668 block_info *src_blk = &fn->blocks[src];
1399 unsigned mark_catches = 0; 1669 unsigned mark_catches = 0;
1400 struct arc_info *arc; 1670 struct arc_info *arc;
1401 1671
1402 if (src >= fn->blocks.size () || fn->blocks[src].succ) 1672 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1403 goto corrupt; 1673 goto corrupt;
1407 unsigned dest = gcov_read_unsigned (); 1677 unsigned dest = gcov_read_unsigned ();
1408 unsigned flags = gcov_read_unsigned (); 1678 unsigned flags = gcov_read_unsigned ();
1409 1679
1410 if (dest >= fn->blocks.size ()) 1680 if (dest >= fn->blocks.size ())
1411 goto corrupt; 1681 goto corrupt;
1412 arc = XCNEW (arc_t); 1682 arc = XCNEW (arc_info);
1413 1683
1414 arc->dst = &fn->blocks[dest]; 1684 arc->dst = &fn->blocks[dest];
1415 arc->src = src_blk; 1685 arc->src = src_blk;
1416 1686
1417 arc->count = 0; 1687 arc->count = 0;
1446 fn->blocks[dest].is_nonlocal_return = 1; 1716 fn->blocks[dest].is_nonlocal_return = 1;
1447 } 1717 }
1448 } 1718 }
1449 1719
1450 if (!arc->on_tree) 1720 if (!arc->on_tree)
1451 fn->num_counts++; 1721 fn->counts.push_back (0);
1452 } 1722 }
1453 1723
1454 if (mark_catches) 1724 if (mark_catches)
1455 { 1725 {
1456 /* We have a fake exit from this block. The other 1726 /* We have a fake exit from this block. The other
1466 } 1736 }
1467 } 1737 }
1468 else if (fn && tag == GCOV_TAG_LINES) 1738 else if (fn && tag == GCOV_TAG_LINES)
1469 { 1739 {
1470 unsigned blockno = gcov_read_unsigned (); 1740 unsigned blockno = gcov_read_unsigned ();
1471 block_t *block = &fn->blocks[blockno]; 1741 block_info *block = &fn->blocks[blockno];
1472 1742
1473 if (blockno >= fn->blocks.size ()) 1743 if (blockno >= fn->blocks.size ())
1474 goto corrupt; 1744 goto corrupt;
1475 1745
1476 while (true) 1746 while (true)
1503 break; 1773 break;
1504 } 1774 }
1505 } 1775 }
1506 gcov_close (); 1776 gcov_close ();
1507 1777
1508 if (!fns) 1778 if (functions.empty ())
1509 fnotice (stderr, "%s:no functions found\n", bbg_file_name); 1779 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1510
1511 return fns;
1512 } 1780 }
1513 1781
1514 /* Reads profiles from the count file and attach to each 1782 /* Reads profiles from the count file and attach to each
1515 function. Return nonzero if fatal error. */ 1783 function. Return nonzero if fatal error. */
1516 1784
1517 static int 1785 static int
1518 read_count_file (function_t *fns) 1786 read_count_file (void)
1519 { 1787 {
1520 unsigned ix; 1788 unsigned ix;
1521 unsigned version; 1789 unsigned version;
1522 unsigned tag; 1790 unsigned tag;
1523 function_t *fn = NULL; 1791 function_info *fn = NULL;
1524 int error = 0; 1792 int error = 0;
1525 1793
1526 if (!gcov_open (da_file_name, 1)) 1794 if (!gcov_open (da_file_name, 1))
1527 { 1795 {
1528 fnotice (stderr, "%s:cannot open data file, assuming not executed\n", 1796 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1558 while ((tag = gcov_read_unsigned ())) 1826 while ((tag = gcov_read_unsigned ()))
1559 { 1827 {
1560 unsigned length = gcov_read_unsigned (); 1828 unsigned length = gcov_read_unsigned ();
1561 unsigned long base = gcov_position (); 1829 unsigned long base = gcov_position ();
1562 1830
1563 if (tag == GCOV_TAG_PROGRAM_SUMMARY) 1831 if (tag == GCOV_TAG_OBJECT_SUMMARY)
1564 { 1832 {
1565 struct gcov_summary summary; 1833 struct gcov_summary summary;
1566 gcov_read_summary (&summary); 1834 gcov_read_summary (&summary);
1567 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs; 1835 object_runs = summary.runs;
1568 program_count++;
1569 } 1836 }
1570 else if (tag == GCOV_TAG_FUNCTION && !length) 1837 else if (tag == GCOV_TAG_FUNCTION && !length)
1571 ; /* placeholder */ 1838 ; /* placeholder */
1572 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH) 1839 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1573 { 1840 {
1574 unsigned ident; 1841 unsigned ident;
1575 struct function_info *fn_n;
1576 1842
1577 /* Try to find the function in the list. To speed up the 1843 /* Try to find the function in the list. To speed up the
1578 search, first start from the last function found. */ 1844 search, first start from the last function found. */
1579 ident = gcov_read_unsigned (); 1845 ident = gcov_read_unsigned ();
1580 fn_n = fns; 1846
1581 for (fn = fn ? fn->next : NULL; ; fn = fn->next) 1847 fn = NULL;
1848 for (vector<function_info *>::reverse_iterator it
1849 = functions.rbegin (); it != functions.rend (); it++)
1582 { 1850 {
1583 if (fn) 1851 if ((*it)->ident == ident)
1584 ;
1585 else if ((fn = fn_n))
1586 fn_n = NULL;
1587 else
1588 { 1852 {
1589 fnotice (stderr, "%s:unknown function '%u'\n", 1853 fn = *it;
1590 da_file_name, ident);
1591 break; 1854 break;
1592 } 1855 }
1593 if (fn->ident == ident)
1594 break;
1595 } 1856 }
1596 1857
1597 if (!fn) 1858 if (!fn)
1598 ; 1859 ;
1599 else if (gcov_read_unsigned () != fn->lineno_checksum 1860 else if (gcov_read_unsigned () != fn->lineno_checksum
1605 goto cleanup; 1866 goto cleanup;
1606 } 1867 }
1607 } 1868 }
1608 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) 1869 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1609 { 1870 {
1610 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) 1871 if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
1611 goto mismatch; 1872 goto mismatch;
1612 1873
1613 if (!fn->counts) 1874 for (ix = 0; ix != fn->counts.size (); ix++)
1614 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1615
1616 for (ix = 0; ix != fn->num_counts; ix++)
1617 fn->counts[ix] += gcov_read_counter (); 1875 fn->counts[ix] += gcov_read_counter ();
1618 } 1876 }
1619 gcov_sync (base, length); 1877 gcov_sync (base, length);
1620 if ((error = gcov_is_error ())) 1878 if ((error = gcov_is_error ()))
1621 { 1879 {
1634 1892
1635 /* Solve the flow graph. Propagate counts from the instrumented arcs 1893 /* Solve the flow graph. Propagate counts from the instrumented arcs
1636 to the blocks and the uninstrumented arcs. */ 1894 to the blocks and the uninstrumented arcs. */
1637 1895
1638 static void 1896 static void
1639 solve_flow_graph (function_t *fn) 1897 solve_flow_graph (function_info *fn)
1640 { 1898 {
1641 unsigned ix; 1899 unsigned ix;
1642 arc_t *arc; 1900 arc_info *arc;
1643 gcov_type *count_ptr = fn->counts; 1901 gcov_type *count_ptr = &fn->counts.front ();
1644 block_t *blk; 1902 block_info *blk;
1645 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ 1903 block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1646 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ 1904 block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1647 1905
1648 /* The arcs were built in reverse order. Fix that now. */ 1906 /* The arcs were built in reverse order. Fix that now. */
1649 for (ix = fn->blocks.size (); ix--;) 1907 for (ix = fn->blocks.size (); ix--;)
1650 { 1908 {
1651 arc_t *arc_p, *arc_n; 1909 arc_info *arc_p, *arc_n;
1652 1910
1653 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; 1911 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1654 arc_p = arc, arc = arc_n) 1912 arc_p = arc, arc = arc_n)
1655 { 1913 {
1656 arc_n = arc->succ_next; 1914 arc_n = arc->succ_next;
1692 /* Propagate the measured counts, this must be done in the same 1950 /* Propagate the measured counts, this must be done in the same
1693 order as the code in profile.c */ 1951 order as the code in profile.c */
1694 for (unsigned i = 0; i < fn->blocks.size (); i++) 1952 for (unsigned i = 0; i < fn->blocks.size (); i++)
1695 { 1953 {
1696 blk = &fn->blocks[i]; 1954 blk = &fn->blocks[i];
1697 block_t const *prev_dst = NULL; 1955 block_info const *prev_dst = NULL;
1698 int out_of_order = 0; 1956 int out_of_order = 0;
1699 int non_fake_succ = 0; 1957 int non_fake_succ = 0;
1700 1958
1701 for (arc = blk->succ; arc; arc = arc->succ_next) 1959 for (arc = blk->succ; arc; arc = arc->succ_next)
1702 { 1960 {
1739 normally produces arcs in the right order, but sometimes with 1997 normally produces arcs in the right order, but sometimes with
1740 one or two out of order. We're not using a particularly 1998 one or two out of order. We're not using a particularly
1741 smart sort. */ 1999 smart sort. */
1742 if (out_of_order) 2000 if (out_of_order)
1743 { 2001 {
1744 arc_t *start = blk->succ; 2002 arc_info *start = blk->succ;
1745 unsigned changes = 1; 2003 unsigned changes = 1;
1746 2004
1747 while (changes) 2005 while (changes)
1748 { 2006 {
1749 arc_t *arc, *arc_p, *arc_n; 2007 arc_info *arc, *arc_p, *arc_n;
1750 2008
1751 changes = 0; 2009 changes = 0;
1752 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) 2010 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1753 { 2011 {
1754 if (arc->dst > arc_n->dst) 2012 if (arc->dst > arc_n->dst)
1782 while (invalid_blocks || valid_blocks) 2040 while (invalid_blocks || valid_blocks)
1783 { 2041 {
1784 while ((blk = invalid_blocks)) 2042 while ((blk = invalid_blocks))
1785 { 2043 {
1786 gcov_type total = 0; 2044 gcov_type total = 0;
1787 const arc_t *arc; 2045 const arc_info *arc;
1788 2046
1789 invalid_blocks = blk->chain; 2047 invalid_blocks = blk->chain;
1790 blk->invalid_chain = 0; 2048 blk->invalid_chain = 0;
1791 if (!blk->num_succ) 2049 if (!blk->num_succ)
1792 for (arc = blk->succ; arc; arc = arc->succ_next) 2050 for (arc = blk->succ; arc; arc = arc->succ_next)
1804 valid_blocks = blk; 2062 valid_blocks = blk;
1805 } 2063 }
1806 while ((blk = valid_blocks)) 2064 while ((blk = valid_blocks))
1807 { 2065 {
1808 gcov_type total; 2066 gcov_type total;
1809 arc_t *arc, *inv_arc; 2067 arc_info *arc, *inv_arc;
1810 2068
1811 valid_blocks = blk->chain; 2069 valid_blocks = blk->chain;
1812 blk->valid_chain = 0; 2070 blk->valid_chain = 0;
1813 if (blk->num_succ == 1) 2071 if (blk->num_succ == 1)
1814 { 2072 {
1815 block_t *dst; 2073 block_info *dst;
1816 2074
1817 total = blk->count; 2075 total = blk->count;
1818 inv_arc = NULL; 2076 inv_arc = NULL;
1819 for (arc = blk->succ; arc; arc = arc->succ_next) 2077 for (arc = blk->succ; arc; arc = arc->succ_next)
1820 { 2078 {
1846 } 2104 }
1847 } 2105 }
1848 } 2106 }
1849 if (blk->num_pred == 1) 2107 if (blk->num_pred == 1)
1850 { 2108 {
1851 block_t *src; 2109 block_info *src;
1852 2110
1853 total = blk->count; 2111 total = blk->count;
1854 inv_arc = NULL; 2112 inv_arc = NULL;
1855 for (arc = blk->pred; arc; arc = arc->pred_next) 2113 for (arc = blk->pred; arc; arc = arc->pred_next)
1856 { 2114 {
1897 } 2155 }
1898 2156
1899 /* Mark all the blocks only reachable via an incoming catch. */ 2157 /* Mark all the blocks only reachable via an incoming catch. */
1900 2158
1901 static void 2159 static void
1902 find_exception_blocks (function_t *fn) 2160 find_exception_blocks (function_info *fn)
1903 { 2161 {
1904 unsigned ix; 2162 unsigned ix;
1905 block_t **queue = XALLOCAVEC (block_t *, fn->blocks.size ()); 2163 block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
1906 2164
1907 /* First mark all blocks as exceptional. */ 2165 /* First mark all blocks as exceptional. */
1908 for (ix = fn->blocks.size (); ix--;) 2166 for (ix = fn->blocks.size (); ix--;)
1909 fn->blocks[ix].exceptional = 1; 2167 fn->blocks[ix].exceptional = 1;
1910 2168
1911 /* Now mark all the blocks reachable via non-fake edges */ 2169 /* Now mark all the blocks reachable via non-fake edges */
1912 queue[0] = &fn->blocks[0]; 2170 queue[0] = &fn->blocks[0];
1913 queue[0]->exceptional = 0; 2171 queue[0]->exceptional = 0;
1914 for (ix = 1; ix;) 2172 for (ix = 1; ix;)
1915 { 2173 {
1916 block_t *block = queue[--ix]; 2174 block_info *block = queue[--ix];
1917 const arc_t *arc; 2175 const arc_info *arc;
1918 2176
1919 for (arc = block->succ; arc; arc = arc->succ_next) 2177 for (arc = block->succ; arc; arc = arc->succ_next)
1920 if (!arc->fake && !arc->is_throw && arc->dst->exceptional) 2178 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1921 { 2179 {
1922 arc->dst->exceptional = 0; 2180 arc->dst->exceptional = 0;
1927 2185
1928 2186
1929 /* Increment totals in COVERAGE according to arc ARC. */ 2187 /* Increment totals in COVERAGE according to arc ARC. */
1930 2188
1931 static void 2189 static void
1932 add_branch_counts (coverage_t *coverage, const arc_t *arc) 2190 add_branch_counts (coverage_info *coverage, const arc_info *arc)
1933 { 2191 {
1934 if (arc->is_call_non_return) 2192 if (arc->is_call_non_return)
1935 { 2193 {
1936 coverage->calls++; 2194 coverage->calls++;
1937 if (arc->src->count) 2195 if (arc->src->count)
1945 if (arc->count) 2203 if (arc->count)
1946 coverage->branches_taken++; 2204 coverage->branches_taken++;
1947 } 2205 }
1948 } 2206 }
1949 2207
2208 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2209 readable format. */
2210
2211 static char const *
2212 format_count (gcov_type count)
2213 {
2214 static char buffer[64];
2215 const char *units = " kMGTPEZY";
2216
2217 if (count < 1000 || !flag_human_readable_numbers)
2218 {
2219 sprintf (buffer, "%" PRId64, count);
2220 return buffer;
2221 }
2222
2223 unsigned i;
2224 gcov_type divisor = 1;
2225 for (i = 0; units[i+1]; i++, divisor *= 1000)
2226 {
2227 if (count + divisor / 2 < 1000 * divisor)
2228 break;
2229 }
2230 float r = 1.0f * count / divisor;
2231 sprintf (buffer, "%.1f%c", r, units[i]);
2232 return buffer;
2233 }
2234
1950 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute 2235 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1951 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. 2236 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
1952 If DP is zero, no decimal point is printed. Only print 100% when 2237 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
1953 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply 2238 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
1954 format TOP. Return pointer to a static string. */ 2239 format TOP. Return pointer to a static string. */
1955 2240
1956 static char const * 2241 static char const *
1957 format_gcov (gcov_type top, gcov_type bottom, int dp) 2242 format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
1958 { 2243 {
1959 static char buffer[20]; 2244 static char buffer[20];
1960 2245
1961 /* Handle invalid values that would result in a misleading value. */ 2246 if (decimal_places >= 0)
1962 if (bottom != 0 && top > bottom && dp >= 0) 2247 {
1963 { 2248 float ratio = bottom ? 100.0f * top / bottom: 0;
1964 sprintf (buffer, "NAN %%"); 2249
1965 return buffer; 2250 /* Round up to 1% if there's a small non-zero value. */
1966 } 2251 if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
1967 2252 ratio = 1.0f;
1968 if (dp >= 0) 2253 sprintf (buffer, "%.*f%%", decimal_places, ratio);
1969 {
1970 float ratio = bottom ? (float)top / bottom : 0;
1971 int ix;
1972 unsigned limit = 100;
1973 unsigned percent;
1974
1975 for (ix = dp; ix--; )
1976 limit *= 10;
1977
1978 percent = (unsigned) (ratio * limit + (float)0.5);
1979 if (percent <= 0 && top)
1980 percent = 1;
1981 else if (percent >= limit && top != bottom)
1982 percent = limit - 1;
1983 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1984 if (dp)
1985 {
1986 dp++;
1987 do
1988 {
1989 buffer[ix+1] = buffer[ix];
1990 ix--;
1991 }
1992 while (dp--);
1993 buffer[ix + 1] = '.';
1994 }
1995 } 2254 }
1996 else 2255 else
1997 sprintf (buffer, "%" PRId64, (int64_t)top); 2256 return format_count (top);
1998 2257
1999 return buffer; 2258 return buffer;
2000 } 2259 }
2001 2260
2002 /* Summary of execution */ 2261 /* Summary of execution */
2012 } 2271 }
2013 2272
2014 /* Output summary info for a function or file. */ 2273 /* Output summary info for a function or file. */
2015 2274
2016 static void 2275 static void
2017 function_summary (const coverage_t *coverage, const char *title) 2276 function_summary (const coverage_info *coverage, const char *title)
2018 { 2277 {
2019 fnotice (stdout, "%s '%s'\n", title, coverage->name); 2278 fnotice (stdout, "%s '%s'\n", title, coverage->name);
2020 executed_summary (coverage->lines, coverage->lines_executed); 2279 executed_summary (coverage->lines, coverage->lines_executed);
2021 2280
2022 if (flag_branches) 2281 if (flag_branches)
2204 len = strlen (base); 2463 len = strlen (base);
2205 memcpy (ptr, base, len); 2464 memcpy (ptr, base, len);
2206 ptr += len; 2465 ptr += len;
2207 } 2466 }
2208 else 2467 else
2209 { 2468 ptr = mangle_path (base);
2210 /* Convert '/' to '#', convert '..' to '^',
2211 convert ':' to '~' on DOS based file system. */
2212 const char *probe;
2213
2214 #if HAVE_DOS_BASED_FILE_SYSTEM
2215 if (base[0] && base[1] == ':')
2216 {
2217 ptr[0] = base[0];
2218 ptr[1] = '~';
2219 ptr += 2;
2220 base += 2;
2221 }
2222 #endif
2223 for (; *base; base = probe)
2224 {
2225 size_t len;
2226
2227 for (probe = base; *probe; probe++)
2228 if (*probe == '/')
2229 break;
2230 len = probe - base;
2231 if (len == 2 && base[0] == '.' && base[1] == '.')
2232 *ptr++ = '^';
2233 else
2234 {
2235 memcpy (ptr, base, len);
2236 ptr += len;
2237 }
2238 if (*probe)
2239 {
2240 *ptr++ = '#';
2241 probe++;
2242 }
2243 }
2244 }
2245 2469
2246 return ptr; 2470 return ptr;
2247 } 2471 }
2248 2472
2249 /* Scan through the bb_data for each line in the block, increment 2473 /* Scan through the bb_data for each line in the block, increment
2250 the line number execution count indicated by the execution count of 2474 the line number execution count indicated by the execution count of
2251 the appropriate basic block. */ 2475 the appropriate basic block. */
2252 2476
2253 static void 2477 static void
2254 add_line_counts (coverage_t *coverage, function_t *fn) 2478 add_line_counts (coverage_info *coverage, function_info *fn)
2255 { 2479 {
2256 bool has_any_line = false; 2480 bool has_any_line = false;
2257 /* Scan each basic block. */ 2481 /* Scan each basic block. */
2258 for (unsigned ix = 0; ix != fn->blocks.size (); ix++) 2482 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2259 { 2483 {
2260 line_t *line = NULL; 2484 line_info *line = NULL;
2261 block_t *block = &fn->blocks[ix]; 2485 block_info *block = &fn->blocks[ix];
2262 if (block->count && ix && ix + 1 != fn->blocks.size ()) 2486 if (block->count && ix && ix + 1 != fn->blocks.size ())
2263 fn->blocks_executed++; 2487 fn->blocks_executed++;
2264 for (unsigned i = 0; i < block->locations.size (); i++) 2488 for (unsigned i = 0; i < block->locations.size (); i++)
2265 { 2489 {
2266 const source_t *src = &sources[block->locations[i].source_file_idx]; 2490 unsigned src_idx = block->locations[i].source_file_idx;
2267
2268 vector<unsigned> &lines = block->locations[i].lines; 2491 vector<unsigned> &lines = block->locations[i].lines;
2492
2493 block->cycle.arc = NULL;
2494 block->cycle.ident = ~0U;
2495
2269 for (unsigned j = 0; j < lines.size (); j++) 2496 for (unsigned j = 0; j < lines.size (); j++)
2270 { 2497 {
2271 line = &src->lines[lines[j]]; 2498 unsigned ln = lines[j];
2272 if (coverage) 2499
2500 /* Line belongs to a function that is in a group. */
2501 if (fn->group_line_p (ln, src_idx))
2273 { 2502 {
2274 if (!line->exists) 2503 gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2275 coverage->lines++; 2504 line = &(fn->lines[lines[j] - fn->start_line]);
2276 if (!line->count && block->count) 2505 line->exists = 1;
2277 coverage->lines_executed++; 2506 if (!block->exceptional)
2507 {
2508 line->unexceptional = 1;
2509 if (block->count == 0)
2510 line->has_unexecuted_block = 1;
2511 }
2512 line->count += block->count;
2278 } 2513 }
2279 line->exists = 1; 2514 else
2280 if (!block->exceptional)
2281 line->unexceptional = 1;
2282 line->count += block->count;
2283 }
2284 }
2285 block->cycle.arc = NULL;
2286 block->cycle.ident = ~0U;
2287 has_any_line = true;
2288
2289 if (!ix || ix + 1 == fn->blocks.size ())
2290 /* Entry or exit block */;
2291 else if (line != NULL)
2292 {
2293 block->chain = line->blocks;
2294 line->blocks = block;
2295
2296 if (flag_branches)
2297 {
2298 arc_t *arc;
2299
2300 for (arc = block->succ; arc; arc = arc->succ_next)
2301 { 2515 {
2302 arc->line_next = line->branches; 2516 gcc_assert (ln < sources[src_idx].lines.size ());
2303 line->branches = arc; 2517 line = &(sources[src_idx].lines[ln]);
2304 if (coverage && !arc->is_unconditional) 2518 if (coverage)
2305 add_branch_counts (coverage, arc); 2519 {
2520 if (!line->exists)
2521 coverage->lines++;
2522 if (!line->count && block->count)
2523 coverage->lines_executed++;
2524 }
2525 line->exists = 1;
2526 if (!block->exceptional)
2527 {
2528 line->unexceptional = 1;
2529 if (block->count == 0)
2530 line->has_unexecuted_block = 1;
2531 }
2532 line->count += block->count;
2306 } 2533 }
2307 } 2534 }
2535
2536 has_any_line = true;
2537
2538 if (!ix || ix + 1 == fn->blocks.size ())
2539 /* Entry or exit block. */;
2540 else if (line != NULL)
2541 {
2542 line->blocks.push_back (block);
2543
2544 if (flag_branches)
2545 {
2546 arc_info *arc;
2547
2548 for (arc = block->succ; arc; arc = arc->succ_next)
2549 line->branches.push_back (arc);
2550 }
2551 }
2308 } 2552 }
2309 } 2553 }
2310 2554
2311 if (!has_any_line) 2555 if (!has_any_line)
2312 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name); 2556 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2313 } 2557 }
2314 2558
2559 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2560 is set to true, update source file summary. */
2561
2562 static void accumulate_line_info (line_info *line, source_info *src,
2563 bool add_coverage)
2564 {
2565 if (add_coverage)
2566 for (vector<arc_info *>::iterator it = line->branches.begin ();
2567 it != line->branches.end (); it++)
2568 add_branch_counts (&src->coverage, *it);
2569
2570 if (!line->blocks.empty ())
2571 {
2572 /* The user expects the line count to be the number of times
2573 a line has been executed. Simply summing the block count
2574 will give an artificially high number. The Right Thing
2575 is to sum the entry counts to the graph of blocks on this
2576 line, then find the elementary cycles of the local graph
2577 and add the transition counts of those cycles. */
2578 gcov_type count = 0;
2579
2580 /* Cycle detection. */
2581 for (vector<block_info *>::iterator it = line->blocks.begin ();
2582 it != line->blocks.end (); it++)
2583 {
2584 for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2585 if (!line->has_block (arc->src))
2586 count += arc->count;
2587 for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2588 arc->cs_count = arc->count;
2589 }
2590
2591 /* Now, add the count of loops entirely on this line. */
2592 count += get_cycles_count (*line);
2593 line->count = count;
2594
2595 if (line->count > src->maximum_count)
2596 src->maximum_count = line->count;
2597 }
2598
2599 if (line->exists && add_coverage)
2600 {
2601 src->coverage.lines++;
2602 if (line->count)
2603 src->coverage.lines_executed++;
2604 }
2605 }
2606
2315 /* Accumulate the line counts of a file. */ 2607 /* Accumulate the line counts of a file. */
2316 2608
2317 static void 2609 static void
2318 accumulate_line_counts (source_t *src) 2610 accumulate_line_counts (source_info *src)
2319 { 2611 {
2320 line_t *line; 2612 /* First work on group functions. */
2321 function_t *fn, *fn_p, *fn_n; 2613 for (vector<function_info *>::iterator it = src->functions.begin ();
2322 unsigned ix; 2614 it != src->functions.end (); it++)
2323 2615 {
2324 /* Reverse the function order. */ 2616 function_info *fn = *it;
2325 for (fn = src->functions, fn_p = NULL; fn; fn_p = fn, fn = fn_n) 2617
2326 { 2618 if (fn->src != src->index || !fn->is_group)
2327 fn_n = fn->next_file_fn; 2619 continue;
2328 fn->next_file_fn = fn_p; 2620
2329 } 2621 for (vector<line_info>::iterator it2 = fn->lines.begin ();
2330 src->functions = fn_p; 2622 it2 != fn->lines.end (); it2++)
2331 2623 {
2332 for (ix = src->num_lines, line = src->lines; ix--; line++) 2624 line_info *line = &(*it2);
2333 { 2625 accumulate_line_info (line, src, false);
2334 if (line->blocks) 2626 }
2335 { 2627 }
2336 /* The user expects the line count to be the number of times 2628
2337 a line has been executed. Simply summing the block count 2629 /* Work on global lines that line in source file SRC. */
2338 will give an artificially high number. The Right Thing 2630 for (vector<line_info>::iterator it = src->lines.begin ();
2339 is to sum the entry counts to the graph of blocks on this 2631 it != src->lines.end (); it++)
2340 line, then find the elementary cycles of the local graph 2632 accumulate_line_info (&(*it), src, true);
2341 and add the transition counts of those cycles. */ 2633
2342 block_t *block, *block_p, *block_n; 2634 /* If not using intermediate mode, sum lines of group functions and
2343 gcov_type count = 0; 2635 add them to lines that live in a source file. */
2344 2636 if (!flag_intermediate_format)
2345 /* Reverse the block information. */ 2637 for (vector<function_info *>::iterator it = src->functions.begin ();
2346 for (block = line->blocks, block_p = NULL; block; 2638 it != src->functions.end (); it++)
2347 block_p = block, block = block_n) 2639 {
2348 { 2640 function_info *fn = *it;
2349 block_n = block->chain; 2641
2350 block->chain = block_p; 2642 if (fn->src != src->index || !fn->is_group)
2351 block->cycle.ident = ix; 2643 continue;
2352 } 2644
2353 line->blocks = block_p; 2645 for (unsigned i = 0; i < fn->lines.size (); i++)
2354 2646 {
2355 /* Sum the entry arcs. */ 2647 line_info *fn_line = &fn->lines[i];
2356 for (block = line->blocks; block; block = block->chain) 2648 if (fn_line->exists)
2357 { 2649 {
2358 arc_t *arc; 2650 unsigned ln = fn->start_line + i;
2359 2651 line_info *src_line = &src->lines[ln];
2360 for (arc = block->pred; arc; arc = arc->pred_next) 2652
2361 if (flag_branches) 2653 if (!src_line->exists)
2362 add_branch_counts (&src->coverage, arc); 2654 src->coverage.lines++;
2363 } 2655 if (!src_line->count && fn_line->count)
2364 2656 src->coverage.lines_executed++;
2365 /* Cycle detection. */ 2657
2366 for (block = line->blocks; block; block = block->chain) 2658 src_line->count += fn_line->count;
2367 { 2659 src_line->exists = 1;
2368 for (arc_t *arc = block->pred; arc; arc = arc->pred_next) 2660
2369 if (!line->has_block (arc->src)) 2661 if (fn_line->has_unexecuted_block)
2370 count += arc->count; 2662 src_line->has_unexecuted_block = 1;
2371 for (arc_t *arc = block->succ; arc; arc = arc->succ_next) 2663
2372 arc->cs_count = arc->count; 2664 if (fn_line->unexceptional)
2373 } 2665 src_line->unexceptional = 1;
2374 2666 }
2375 /* Now, add the count of loops entirely on this line. */ 2667 }
2376 count += get_cycles_count (*line); 2668 }
2377 line->count = count;
2378 }
2379
2380 if (line->exists)
2381 {
2382 src->coverage.lines++;
2383 if (line->count)
2384 src->coverage.lines_executed++;
2385 }
2386 }
2387 } 2669 }
2388 2670
2389 /* Output information about ARC number IX. Returns nonzero if 2671 /* Output information about ARC number IX. Returns nonzero if
2390 anything is output. */ 2672 anything is output. */
2391 2673
2392 static int 2674 static int
2393 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) 2675 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2394 { 2676 {
2395 if (arc->is_call_non_return) 2677 if (arc->is_call_non_return)
2396 { 2678 {
2397 if (arc->src->count) 2679 if (arc->src->count)
2398 { 2680 {
2466 } 2748 }
2467 2749
2468 return pos ? string : NULL; 2750 return pos ? string : NULL;
2469 } 2751 }
2470 2752
2753 /* Pad string S with spaces from left to have total width equal to 9. */
2754
2755 static void
2756 pad_count_string (string &s)
2757 {
2758 if (s.size () < 9)
2759 s.insert (0, 9 - s.size (), ' ');
2760 }
2761
2762 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2763 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2764 an exceptional statement. The output is printed for LINE_NUM of given
2765 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2766 used to indicate non-executed blocks. */
2767
2768 static void
2769 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2770 bool has_unexecuted_block,
2771 gcov_type count, unsigned line_num,
2772 const char *exceptional_string,
2773 const char *unexceptional_string,
2774 unsigned int maximum_count)
2775 {
2776 string s;
2777 if (exists)
2778 {
2779 if (count > 0)
2780 {
2781 s = format_gcov (count, 0, -1);
2782 if (has_unexecuted_block
2783 && bbg_supports_has_unexecuted_blocks)
2784 {
2785 if (flag_use_colors)
2786 {
2787 pad_count_string (s);
2788 s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2789 COLOR_SEPARATOR COLOR_FG_WHITE));
2790 s += SGR_RESET;
2791 }
2792 else
2793 s += "*";
2794 }
2795 pad_count_string (s);
2796 }
2797 else
2798 {
2799 if (flag_use_colors)
2800 {
2801 s = "0";
2802 pad_count_string (s);
2803 if (unexceptional)
2804 s.insert (0, SGR_SEQ (COLOR_BG_RED
2805 COLOR_SEPARATOR COLOR_FG_WHITE));
2806 else
2807 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
2808 COLOR_SEPARATOR COLOR_FG_WHITE));
2809 s += SGR_RESET;
2810 }
2811 else
2812 {
2813 s = unexceptional ? unexceptional_string : exceptional_string;
2814 pad_count_string (s);
2815 }
2816 }
2817 }
2818 else
2819 {
2820 s = "-";
2821 pad_count_string (s);
2822 }
2823
2824 /* Format line number in output. */
2825 char buffer[16];
2826 sprintf (buffer, "%5u", line_num);
2827 string linestr (buffer);
2828
2829 if (flag_use_hotness_colors && maximum_count)
2830 {
2831 if (count * 2 > maximum_count) /* > 50%. */
2832 linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
2833 else if (count * 5 > maximum_count) /* > 20%. */
2834 linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
2835 else if (count * 10 > maximum_count) /* > 10%. */
2836 linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
2837 linestr += SGR_RESET;
2838 }
2839
2840 fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
2841 }
2842
2843 static void
2844 print_source_line (FILE *f, const vector<const char *> &source_lines,
2845 unsigned line)
2846 {
2847 gcc_assert (line >= 1);
2848 gcc_assert (line <= source_lines.size ());
2849
2850 fprintf (f, ":%s\n", source_lines[line - 1]);
2851 }
2852
2853 /* Output line details for LINE and print it to F file. LINE lives on
2854 LINE_NUM. */
2855
2856 static void
2857 output_line_details (FILE *f, const line_info *line, unsigned line_num)
2858 {
2859 if (flag_all_blocks)
2860 {
2861 arc_info *arc;
2862 int ix, jx;
2863
2864 ix = jx = 0;
2865 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
2866 it != line->blocks.end (); it++)
2867 {
2868 if (!(*it)->is_call_return)
2869 {
2870 output_line_beginning (f, line->exists,
2871 (*it)->exceptional, false,
2872 (*it)->count, line_num,
2873 "%%%%%", "$$$$$", 0);
2874 fprintf (f, "-block %2d", ix++);
2875 if (flag_verbose)
2876 fprintf (f, " (BB %u)", (*it)->id);
2877 fprintf (f, "\n");
2878 }
2879 if (flag_branches)
2880 for (arc = (*it)->succ; arc; arc = arc->succ_next)
2881 jx += output_branch_count (f, jx, arc);
2882 }
2883 }
2884 else if (flag_branches)
2885 {
2886 int ix;
2887
2888 ix = 0;
2889 for (vector<arc_info *>::const_iterator it = line->branches.begin ();
2890 it != line->branches.end (); it++)
2891 ix += output_branch_count (f, ix, (*it));
2892 }
2893 }
2894
2895 /* Output detail statistics about function FN to file F. */
2896
2897 static void
2898 output_function_details (FILE *f, const function_info *fn)
2899 {
2900 if (!flag_branches)
2901 return;
2902
2903 arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
2904 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2905 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2906
2907 for (; arc; arc = arc->pred_next)
2908 if (arc->fake)
2909 return_count -= arc->count;
2910
2911 fprintf (f, "function %s",
2912 flag_demangled_names ? fn->demangled_name : fn->name);
2913 fprintf (f, " called %s",
2914 format_gcov (called_count, 0, -1));
2915 fprintf (f, " returned %s",
2916 format_gcov (return_count, called_count, 0));
2917 fprintf (f, " blocks executed %s",
2918 format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
2919 0));
2920 fprintf (f, "\n");
2921 }
2922
2471 /* Read in the source file one line at a time, and output that line to 2923 /* Read in the source file one line at a time, and output that line to
2472 the gcov file preceded by its execution count and other 2924 the gcov file preceded by its execution count and other
2473 information. */ 2925 information. */
2474 2926
2475 static void 2927 static void
2476 output_lines (FILE *gcov_file, const source_t *src) 2928 output_lines (FILE *gcov_file, const source_info *src)
2477 { 2929 {
2930 #define DEFAULT_LINE_START " -: 0:"
2931 #define FN_SEPARATOR "------------------\n"
2932
2478 FILE *source_file; 2933 FILE *source_file;
2479 unsigned line_num; /* current line number. */ 2934 const char *retval;
2480 const line_t *line; /* current line info ptr. */ 2935
2481 const char *retval = ""; /* status of source file reading. */ 2936 /* Print colorization legend. */
2482 function_t *fn = NULL; 2937 if (flag_use_colors)
2483 2938 fprintf (gcov_file, "%s",
2484 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name); 2939 DEFAULT_LINE_START "Colorization: profile count: " \
2940 SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
2941 " " \
2942 SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
2943 " " \
2944 SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
2945
2946 if (flag_use_hotness_colors)
2947 fprintf (gcov_file, "%s",
2948 DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
2949 SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
2950 SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
2951 SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
2952
2953 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
2954
2955 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
2485 if (!multiple_files) 2956 if (!multiple_files)
2486 { 2957 {
2487 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name); 2958 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
2488 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, 2959 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
2489 no_data_file ? "-" : da_file_name); 2960 no_data_file ? "-" : da_file_name);
2490 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs); 2961 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
2491 } 2962 }
2492 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
2493 2963
2494 source_file = fopen (src->name, "r"); 2964 source_file = fopen (src->name, "r");
2495 if (!source_file) 2965 if (!source_file)
2496 { 2966 fnotice (stderr, "Cannot open source file %s\n", src->name);
2497 fnotice (stderr, "Cannot open source file %s\n", src->name);
2498 retval = NULL;
2499 }
2500 else if (src->file_time == 0) 2967 else if (src->file_time == 0)
2501 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0); 2968 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
2502 2969
2503 if (flag_branches) 2970 vector<const char *> source_lines;
2504 fn = src->functions; 2971 if (source_file)
2505 2972 while ((retval = read_line (source_file)) != NULL)
2506 for (line_num = 1, line = &src->lines[line_num]; 2973 source_lines.push_back (xstrdup (retval));
2507 line_num < src->num_lines; line_num++, line++) 2974
2508 { 2975 unsigned line_start_group = 0;
2509 for (; fn && fn->line == line_num; fn = fn->next_file_fn) 2976 vector<function_info *> fns;
2510 { 2977
2511 arc_t *arc = fn->blocks[EXIT_BLOCK].pred; 2978 for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
2512 gcov_type return_count = fn->blocks[EXIT_BLOCK].count; 2979 {
2513 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count; 2980 if (line_num >= src->lines.size ())
2514 2981 {
2515 for (; arc; arc = arc->pred_next) 2982 fprintf (gcov_file, "%9s:%5u", "-", line_num);
2516 if (arc->fake) 2983 print_source_line (gcov_file, source_lines, line_num);
2517 return_count -= arc->count; 2984 continue;
2518 2985 }
2519 fprintf (gcov_file, "function %s", flag_demangled_names ? 2986
2520 fn->demangled_name : fn->name); 2987 const line_info *line = &src->lines[line_num];
2521 fprintf (gcov_file, " called %s", 2988
2522 format_gcov (called_count, 0, -1)); 2989 if (line_start_group == 0)
2523 fprintf (gcov_file, " returned %s", 2990 {
2524 format_gcov (return_count, called_count, 0)); 2991 fns = src->get_functions_at_location (line_num);
2525 fprintf (gcov_file, " blocks executed %s", 2992 if (fns.size () > 1)
2526 format_gcov (fn->blocks_executed, fn->blocks.size () - 2, 2993 {
2527 0)); 2994 /* It's possible to have functions that partially overlap,
2528 fprintf (gcov_file, "\n"); 2995 thus take the maximum end_line of functions starting
2529 } 2996 at LINE_NUM. */
2530 2997 for (unsigned i = 0; i < fns.size (); i++)
2531 if (retval) 2998 if (fns[i]->end_line > line_start_group)
2532 retval = read_line (source_file); 2999 line_start_group = fns[i]->end_line;
3000 }
3001 else if (fns.size () == 1)
3002 {
3003 function_info *fn = fns[0];
3004 output_function_details (gcov_file, fn);
3005 }
3006 }
2533 3007
2534 /* For lines which don't exist in the .bb file, print '-' before 3008 /* For lines which don't exist in the .bb file, print '-' before
2535 the source line. For lines which exist but were never 3009 the source line. For lines which exist but were never
2536 executed, print '#####' or '=====' before the source line. 3010 executed, print '#####' or '=====' before the source line.
2537 Otherwise, print the execution count before the source line. 3011 Otherwise, print the execution count before the source line.
2538 There are 16 spaces of indentation added before the source 3012 There are 16 spaces of indentation added before the source
2539 line so that tabs won't be messed up. */ 3013 line so that tabs won't be messed up. */
2540 fprintf (gcov_file, "%9s:%5u:%s\n", 3014 output_line_beginning (gcov_file, line->exists, line->unexceptional,
2541 !line->exists ? "-" : line->count 3015 line->has_unexecuted_block, line->count,
2542 ? format_gcov (line->count, 0, -1) 3016 line_num, "=====", "#####", src->maximum_count);
2543 : line->unexceptional ? "#####" : "=====", line_num, 3017
2544 retval ? retval : "/*EOF*/"); 3018 print_source_line (gcov_file, source_lines, line_num);
2545 3019 output_line_details (gcov_file, line, line_num);
2546 if (flag_all_blocks) 3020
2547 { 3021 if (line_start_group == line_num)
2548 block_t *block; 3022 {
2549 arc_t *arc; 3023 for (vector<function_info *>::iterator it = fns.begin ();
2550 int ix, jx; 3024 it != fns.end (); it++)
2551
2552 for (ix = jx = 0, block = line->blocks; block;
2553 block = block->chain)
2554 { 3025 {
2555 if (!block->is_call_return) 3026 function_info *fn = *it;
3027 vector<line_info> &lines = fn->lines;
3028
3029 fprintf (gcov_file, FN_SEPARATOR);
3030
3031 string fn_name
3032 = flag_demangled_names ? fn->demangled_name : fn->name;
3033
3034 if (flag_use_colors)
2556 { 3035 {
2557 fprintf (gcov_file, "%9s:%5u-block %2d", 3036 fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
2558 !line->exists ? "-" : block->count 3037 fn_name += SGR_RESET;
2559 ? format_gcov (block->count, 0, -1)
2560 : block->exceptional ? "%%%%%" : "$$$$$",
2561 line_num, ix++);
2562 if (flag_verbose)
2563 fprintf (gcov_file, " (BB %u)", block->id);
2564 fprintf (gcov_file, "\n");
2565 } 3038 }
2566 if (flag_branches) 3039
2567 for (arc = block->succ; arc; arc = arc->succ_next) 3040 fprintf (gcov_file, "%s:\n", fn_name.c_str ());
2568 jx += output_branch_count (gcov_file, jx, arc); 3041
3042 output_function_details (gcov_file, fn);
3043
3044 /* Print all lines covered by the function. */
3045 for (unsigned i = 0; i < lines.size (); i++)
3046 {
3047 line_info *line = &lines[i];
3048 unsigned l = fn->start_line + i;
3049
3050 /* For lines which don't exist in the .bb file, print '-'
3051 before the source line. For lines which exist but
3052 were never executed, print '#####' or '=====' before
3053 the source line. Otherwise, print the execution count
3054 before the source line.
3055 There are 16 spaces of indentation added before the source
3056 line so that tabs won't be messed up. */
3057 output_line_beginning (gcov_file, line->exists,
3058 line->unexceptional,
3059 line->has_unexecuted_block,
3060 line->count,
3061 l, "=====", "#####",
3062 src->maximum_count);
3063
3064 print_source_line (gcov_file, source_lines, l);
3065 output_line_details (gcov_file, line, l);
3066 }
2569 } 3067 }
2570 } 3068
2571 else if (flag_branches) 3069 fprintf (gcov_file, FN_SEPARATOR);
2572 { 3070 line_start_group = 0;
2573 int ix; 3071 }
2574 arc_t *arc;
2575
2576 for (ix = 0, arc = line->branches; arc; arc = arc->line_next)
2577 ix += output_branch_count (gcov_file, ix, arc);
2578 }
2579 }
2580
2581 /* Handle all remaining source lines. There may be lines after the
2582 last line of code. */
2583 if (retval)
2584 {
2585 for (; (retval = read_line (source_file)); line_num++)
2586 fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
2587 } 3072 }
2588 3073
2589 if (source_file) 3074 if (source_file)
2590 fclose (source_file); 3075 fclose (source_file);
2591 } 3076 }