Mercurial > hg > CbC > CbC_gcc
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 } |