1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990-2016 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support.
6 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
7
8 Gcov is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 Gcov is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Gcov; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 /* ??? Print a list of the ten blocks with the highest execution counts,
23 and list the line numbers corresponding to those blocks. Also, perhaps
24 list the line numbers with the highest execution counts, only printing
25 the first if there are several which are all listed in the same block. */
26
27 /* ??? Should have an option to print the number of basic blocks, and the
28 percent of them that are covered. */
29
30 /* Need an option to show individual block counts, and show
31 probabilities of fall through arcs. */
32
33 #include "config.h"
34 #include "system.h"
35 #include "coretypes.h"
36 #include "tm.h"
37 #include "intl.h"
38 #include "diagnostic.h"
39 #include "version.h"
40 #include "demangle.h"
41
42 #include <getopt.h>
43
44 #define IN_GCOV 1
45 #include "gcov-io.h"
46 #include "gcov-io.c"
47
48 /* The gcno file is generated by -ftest-coverage option. The gcda file is
49 generated by a program compiled with -fprofile-arcs. Their formats
50 are documented in gcov-io.h. */
51
52 /* The functions in this file for creating and solution program flow graphs
53 are very similar to functions in the gcc source file profile.c. In
54 some places we make use of the knowledge of how profile.c works to
55 select particular algorithms here. */
56
57 /* The code validates that the profile information read in corresponds
58 to the code currently being compiled. Rather than checking for
59 identical files, the code below compares a checksum on the CFG
60 (based on the order of basic blocks and the arcs in the CFG). If
61 the CFG checksum in the gcda file match the CFG checksum in the
62 gcno file, the profile data will be used. */
63
64 /* This is the size of the buffer used to read in source file lines. */
65
66 struct function_info;
67 struct block_info;
68 struct source_info;
69
70 /* Describes an arc between two basic blocks. */
71
72 typedef struct arc_info
73 {
74 /* source and destination blocks. */
75 struct block_info *src;
76 struct block_info *dst;
77
78 /* transition counts. */
79 gcov_type count;
80 /* used in cycle search, so that we do not clobber original counts. */
81 gcov_type cs_count;
82
83 unsigned int count_valid : 1;
84 unsigned int on_tree : 1;
85 unsigned int fake : 1;
86 unsigned int fall_through : 1;
87
88 /* Arc to a catch handler. */
89 unsigned int is_throw : 1;
90
91 /* Arc is for a function that abnormally returns. */
92 unsigned int is_call_non_return : 1;
93
94 /* Arc is for catch/setjmp. */
95 unsigned int is_nonlocal_return : 1;
96
97 /* Is an unconditional branch. */
98 unsigned int is_unconditional : 1;
99
100 /* Loop making arc. */
101 unsigned int cycle : 1;
102
103 /* Next branch on line. */
104 struct arc_info *line_next;
105
106 /* Links to next arc on src and dst lists. */
107 struct arc_info *succ_next;
108 struct arc_info *pred_next;
109 } arc_t;
110
111 /* Describes a basic block. Contains lists of arcs to successor and
112 predecessor blocks. */
113
114 typedef struct block_info
115 {
116 /* Chain of exit and entry arcs. */
117 arc_t *succ;
118 arc_t *pred;
119
120 /* Number of unprocessed exit and entry arcs. */
121 gcov_type num_succ;
122 gcov_type num_pred;
123
124 /* Block execution count. */
125 gcov_type count;
126 unsigned flags : 12;
127 unsigned count_valid : 1;
128 unsigned valid_chain : 1;
129 unsigned invalid_chain : 1;
130 unsigned exceptional : 1;
131
132 /* Block is a call instrumenting site. */
133 unsigned is_call_site : 1; /* Does the call. */
134 unsigned is_call_return : 1; /* Is the return. */
135
136 /* Block is a landing pad for longjmp or throw. */
137 unsigned is_nonlocal_return : 1;
138
139 union
140 {
141 struct
142 {
143 /* Array of line numbers and source files. source files are
144 introduced by a linenumber of zero, the next 'line number' is
145 the number of the source file. Always starts with a source
146 file. */
147 unsigned *encoding;
148 unsigned num;
149 } line; /* Valid until blocks are linked onto lines */
150 struct
151 {
152 /* Single line graph cycle workspace. Used for all-blocks
153 mode. */
154 arc_t *arc;
155 unsigned ident;
156 } cycle; /* Used in all-blocks mode, after blocks are linked onto
157 lines. */
158 } u;
159
160 /* Temporary chain for solving graph, and for chaining blocks on one
161 line. */
162 struct block_info *chain;
163
164 } block_t;
165
166 /* Describes a single function. Contains an array of basic blocks. */
167
168 typedef struct function_info
169 {
170 /* Name of function. */
171 char *name;
172 char *demangled_name;
173 unsigned ident;
174 unsigned lineno_checksum;
175 unsigned cfg_checksum;
176
177 /* The graph contains at least one fake incoming edge. */
178 unsigned has_catch : 1;
179
180 /* Array of basic blocks. Like in GCC, the entry block is
181 at blocks[0] and the exit block is at blocks[1]. */
182 #define ENTRY_BLOCK (0)
183 #define EXIT_BLOCK (1)
184 block_t *blocks;
185 unsigned num_blocks;
186 unsigned blocks_executed;
187
188 /* Raw arc coverage counts. */
189 gcov_type *counts;
190 unsigned num_counts;
191
192 /* First line number & file. */
193 unsigned line;
194 unsigned src;
195
196 /* Next function in same source file. */
197 struct function_info *line_next;
198
199 /* Next function. */
200 struct function_info *next;
201 } function_t;
202
203 /* Describes coverage of a file or function. */
204
205 typedef struct coverage_info
206 {
207 int lines;
208 int lines_executed;
209
210 int branches;
211 int branches_executed;
212 int branches_taken;
213
214 int calls;
215 int calls_executed;
216
217 char *name;
218 } coverage_t;
219
220 /* Describes a single line of source. Contains a chain of basic blocks
221 with code on it. */
222
223 typedef struct line_info
224 {
225 gcov_type count; /* execution count */
226 union
227 {
228 arc_t *branches; /* branches from blocks that end on this
229 line. Used for branch-counts when not
230 all-blocks mode. */
231 block_t *blocks; /* blocks which start on this line. Used
232 in all-blocks mode. */
233 } u;
234 unsigned exists : 1;
235 unsigned unexceptional : 1;
236 } line_t;
237
238 /* Describes a file mentioned in the block graph. Contains an array
239 of line info. */
240
241 typedef struct source_info
242 {
243 /* Canonical name of source file. */
244 char *name;
245 time_t file_time;
246
247 /* Array of line information. */
248 line_t *lines;
249 unsigned num_lines;
250
251 coverage_t coverage;
252
253 /* Functions in this source file. These are in ascending line
254 number order. */
255 function_t *functions;
256 } source_t;
257
258 typedef struct name_map
259 {
260 char *name; /* Source file name */
261 unsigned src; /* Source file */
262 } name_map_t;
263
264 /* Holds a list of function basic block graphs. */
265
266 static function_t *functions;
267 static function_t **fn_end = &functions;
268
269 static source_t *sources; /* Array of source files */
270 static unsigned n_sources; /* Number of sources */
271 static unsigned a_sources; /* Allocated sources */
272
273 static name_map_t *names; /* Mapping of file names to sources */
274 static unsigned n_names; /* Number of names */
275 static unsigned a_names; /* Allocated names */
276
277 /* This holds data summary information. */
278
279 static unsigned object_runs;
280 static unsigned program_count;
281
282 static unsigned total_lines;
283 static unsigned total_executed;
284
285 /* Modification time of graph file. */
286
287 static time_t bbg_file_time;
288
289 /* Name of the notes (gcno) output file. The "bbg" prefix is for
290 historical reasons, when the notes file contained only the
291 basic block graph notes. */
292
293 static char *bbg_file_name;
294
295 /* Stamp of the bbg file */
296 static unsigned bbg_stamp;
297
298 /* Name and file pointer of the input file for the count data (gcda). */
299
300 static char *da_file_name;
301
302 /* Data file is missing. */
303
304 static int no_data_file;
305
306 /* If there is several input files, compute and display results after
307 reading all data files. This way if two or more gcda file refer to
308 the same source file (eg inline subprograms in a .h file), the
309 counts are added. */
310
311 static int multiple_files = 0;
312
313 /* Output branch probabilities. */
314
315 static int flag_branches = 0;
316
317 /* Show unconditional branches too. */
318 static int flag_unconditional = 0;
319
320 /* Output a gcov file if this is true. This is on by default, and can
321 be turned off by the -n option. */
322
323 static int flag_gcov_file = 1;
324
325 /* Output progress indication if this is true. This is off by default
326 and can be turned on by the -d option. */
327
328 static int flag_display_progress = 0;
329
330 /* Output *.gcov file in intermediate format used by 'lcov'. */
331
332 static int flag_intermediate_format = 0;
333
334 /* Output demangled function names. */
335
336 static int flag_demangled_names = 0;
337
338 /* For included files, make the gcov output file name include the name
339 of the input source file. For example, if x.h is included in a.c,
340 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
341
342 static int flag_long_names = 0;
343
344 /* Output count information for every basic block, not merely those
345 that contain line number information. */
346
347 static int flag_all_blocks = 0;
348
349 /* Output summary info for each function. */
350
351 static int flag_function_summary = 0;
352
353 /* Object directory file prefix. This is the directory/file where the
354 graph and data files are looked for, if nonzero. */
355
356 static char *object_directory = 0;
357
358 /* Source directory prefix. This is removed from source pathnames
359 that match, when generating the output file name. */
360
361 static char *source_prefix = 0;
362 static size_t source_length = 0;
363
364 /* Only show data for sources with relative pathnames. Absolute ones
365 usually indicate a system header file, which although it may
366 contain inline functions, is usually uninteresting. */
367 static int flag_relative_only = 0;
368
369 /* Preserve all pathname components. Needed when object files and
370 source files are in subdirectories. '/' is mangled as '#', '.' is
371 elided and '..' mangled to '^'. */
372
373 static int flag_preserve_paths = 0;
374
375 /* Output the number of times a branch was taken as opposed to the percentage
376 of times it was taken. */
377
378 static int flag_counts = 0;
379
380 /* Forward declarations. */
381 static int process_args (int, char **);
382 static void print_usage (int) ATTRIBUTE_NORETURN;
383 static void print_version (void) ATTRIBUTE_NORETURN;
384 static void process_file (const char *);
385 static void generate_results (const char *);
386 static void create_file_names (const char *);
387 static int name_search (const void *, const void *);
388 static int name_sort (const void *, const void *);
389 static char *canonicalize_name (const char *);
390 static unsigned find_source (const char *);
391 static function_t *read_graph_file (void);
392 static int read_count_file (function_t *);
393 static void solve_flow_graph (function_t *);
394 static void find_exception_blocks (function_t *);
395 static void add_branch_counts (coverage_t *, const arc_t *);
396 static void add_line_counts (coverage_t *, function_t *);
397 static void executed_summary (unsigned, unsigned);
398 static void function_summary (const coverage_t *, const char *);
399 static const char *format_gcov (gcov_type, gcov_type, int);
400 static void accumulate_line_counts (source_t *);
401 static void output_gcov_file (const char *, source_t *);
402 static int output_branch_count (FILE *, int, const arc_t *);
403 static void output_lines (FILE *, const source_t *);
404 static char *make_gcov_file_name (const char *, const char *);
405 static char *mangle_name (const char *, char *);
406 static void release_structures (void);
407 static void release_function (function_t *);
408 extern int main (int, char **);
409
410 int
main(int argc,char ** argv)411 main (int argc, char **argv)
412 {
413 int argno;
414 int first_arg;
415 const char *p;
416
417 p = argv[0] + strlen (argv[0]);
418 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
419 --p;
420 progname = p;
421
422 xmalloc_set_program_name (progname);
423
424 /* Unlock the stdio streams. */
425 unlock_std_streams ();
426
427 gcc_init_libintl ();
428
429 diagnostic_initialize (global_dc, 0);
430
431 /* Handle response files. */
432 expandargv (&argc, &argv);
433
434 a_names = 10;
435 names = XNEWVEC (name_map_t, a_names);
436 a_sources = 10;
437 sources = XNEWVEC (source_t, a_sources);
438
439 argno = process_args (argc, argv);
440 if (optind == argc)
441 print_usage (true);
442
443 if (argc - argno > 1)
444 multiple_files = 1;
445
446 first_arg = argno;
447
448 for (; argno != argc; argno++)
449 {
450 if (flag_display_progress)
451 printf ("Processing file %d out of %d\n",
452 argno - first_arg + 1, argc - first_arg);
453 process_file (argv[argno]);
454 }
455
456 generate_results (multiple_files ? NULL : argv[argc - 1]);
457
458 release_structures ();
459
460 return 0;
461 }
462
463 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
464 otherwise the output of --help. */
465
466 static void
print_usage(int error_p)467 print_usage (int error_p)
468 {
469 FILE *file = error_p ? stderr : stdout;
470 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
471
472 fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
473 fnotice (file, "Print code coverage information.\n\n");
474 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
475 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
476 fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
477 rather than percentages\n");
478 fnotice (file, " -d, --display-progress Display progress information\n");
479 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
480 fnotice (file, " -h, --help Print this help, then exit\n");
481 fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
482 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
483 source files\n");
484 fnotice (file, " -m, --demangled-names Output demangled function names\n");
485 fnotice (file, " -n, --no-output Do not create an output file\n");
486 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
487 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
488 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
489 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
490 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
491 fnotice (file, " -v, --version Print version number, then exit\n");
492 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
493 bug_report_url);
494 exit (status);
495 }
496
497 /* Print version information and exit. */
498
499 static void
print_version(void)500 print_version (void)
501 {
502 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
503 fprintf (stdout, "Copyright %s 2017 Free Software Foundation, Inc.\n",
504 _("(C)"));
505 fnotice (stdout,
506 _("This is free software; see the source for copying conditions.\n"
507 "There is NO warranty; not even for MERCHANTABILITY or \n"
508 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
509 exit (SUCCESS_EXIT_CODE);
510 }
511
512 static const struct option options[] =
513 {
514 { "help", no_argument, NULL, 'h' },
515 { "version", no_argument, NULL, 'v' },
516 { "all-blocks", no_argument, NULL, 'a' },
517 { "branch-probabilities", no_argument, NULL, 'b' },
518 { "branch-counts", no_argument, NULL, 'c' },
519 { "intermediate-format", no_argument, NULL, 'i' },
520 { "no-output", no_argument, NULL, 'n' },
521 { "long-file-names", no_argument, NULL, 'l' },
522 { "function-summaries", no_argument, NULL, 'f' },
523 { "demangled-names", no_argument, NULL, 'm' },
524 { "preserve-paths", no_argument, NULL, 'p' },
525 { "relative-only", no_argument, NULL, 'r' },
526 { "object-directory", required_argument, NULL, 'o' },
527 { "object-file", required_argument, NULL, 'o' },
528 { "source-prefix", required_argument, NULL, 's' },
529 { "unconditional-branches", no_argument, NULL, 'u' },
530 { "display-progress", no_argument, NULL, 'd' },
531 { 0, 0, 0, 0 }
532 };
533
534 /* Process args, return index to first non-arg. */
535
536 static int
process_args(int argc,char ** argv)537 process_args (int argc, char **argv)
538 {
539 int opt;
540
541 while ((opt = getopt_long (argc, argv, "abcdfhilmno:s:pruv", options, NULL)) !=
542 -1)
543 {
544 switch (opt)
545 {
546 case 'a':
547 flag_all_blocks = 1;
548 break;
549 case 'b':
550 flag_branches = 1;
551 break;
552 case 'c':
553 flag_counts = 1;
554 break;
555 case 'f':
556 flag_function_summary = 1;
557 break;
558 case 'h':
559 print_usage (false);
560 /* print_usage will exit. */
561 case 'l':
562 flag_long_names = 1;
563 break;
564 case 'm':
565 flag_demangled_names = 1;
566 break;
567 case 'n':
568 flag_gcov_file = 0;
569 break;
570 case 'o':
571 object_directory = optarg;
572 break;
573 case 's':
574 source_prefix = optarg;
575 source_length = strlen (source_prefix);
576 break;
577 case 'r':
578 flag_relative_only = 1;
579 break;
580 case 'p':
581 flag_preserve_paths = 1;
582 break;
583 case 'u':
584 flag_unconditional = 1;
585 break;
586 case 'i':
587 flag_intermediate_format = 1;
588 flag_gcov_file = 1;
589 break;
590 case 'd':
591 flag_display_progress = 1;
592 break;
593 case 'v':
594 print_version ();
595 /* print_version will exit. */
596 default:
597 print_usage (true);
598 /* print_usage will exit. */
599 }
600 }
601
602 return optind;
603 }
604
605 /* Output the result in intermediate format used by 'lcov'.
606
607 The intermediate format contains a single file named 'foo.cc.gcov',
608 with no source code included. A sample output is
609
610 file:foo.cc
611 function:5,1,_Z3foov
612 function:13,1,main
613 function:19,1,_GLOBAL__sub_I__Z3foov
614 function:19,1,_Z41__static_initialization_and_destruction_0ii
615 lcount:5,1
616 lcount:7,9
617 lcount:9,8
618 lcount:11,1
619 file:/.../iostream
620 lcount:74,1
621 file:/.../basic_ios.h
622 file:/.../ostream
623 file:/.../ios_base.h
624 function:157,0,_ZStorSt12_Ios_IostateS_
625 lcount:157,0
626 file:/.../char_traits.h
627 function:258,0,_ZNSt11char_traitsIcE6lengthEPKc
628 lcount:258,0
629 ...
630
631 The default gcov outputs multiple files: 'foo.cc.gcov',
632 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
633 included. Instead the intermediate format here outputs only a single
634 file 'foo.cc.gcov' similar to the above example. */
635
636 static void
output_intermediate_file(FILE * gcov_file,source_t * src)637 output_intermediate_file (FILE *gcov_file, source_t *src)
638 {
639 unsigned line_num; /* current line number. */
640 const line_t *line; /* current line info ptr. */
641 function_t *fn; /* current function info ptr. */
642
643 fprintf (gcov_file, "file:%s\n", src->name); /* source file name */
644
645 for (fn = src->functions; fn; fn = fn->line_next)
646 {
647 /* function:<name>,<line_number>,<execution_count> */
648 fprintf (gcov_file, "function:%d,%s,%s\n", fn->line,
649 format_gcov (fn->blocks[0].count, 0, -1),
650 flag_demangled_names ? fn->demangled_name : fn->name);
651 }
652
653 for (line_num = 1, line = &src->lines[line_num];
654 line_num < src->num_lines;
655 line_num++, line++)
656 {
657 arc_t *arc;
658 if (line->exists)
659 fprintf (gcov_file, "lcount:%u,%s\n", line_num,
660 format_gcov (line->count, 0, -1));
661 if (flag_branches)
662 for (arc = line->u.branches; arc; arc = arc->line_next)
663 {
664 if (!arc->is_unconditional && !arc->is_call_non_return)
665 {
666 const char *branch_type;
667 /* branch:<line_num>,<branch_coverage_type>
668 branch_coverage_type
669 : notexec (Branch not executed)
670 : taken (Branch executed and taken)
671 : nottaken (Branch executed, but not taken)
672 */
673 if (arc->src->count)
674 branch_type = (arc->count > 0) ? "taken" : "nottaken";
675 else
676 branch_type = "notexec";
677 fprintf (gcov_file, "branch:%d,%s\n", line_num, branch_type);
678 }
679 }
680 }
681 }
682
683
684 /* Process a single input file. */
685
686 static void
process_file(const char * file_name)687 process_file (const char *file_name)
688 {
689 function_t *fns;
690
691 create_file_names (file_name);
692 fns = read_graph_file ();
693 if (!fns)
694 return;
695
696 read_count_file (fns);
697 while (fns)
698 {
699 function_t *fn = fns;
700
701 fns = fn->next;
702 fn->next = NULL;
703 if (fn->counts || no_data_file)
704 {
705 unsigned src = fn->src;
706 unsigned line = fn->line;
707 unsigned block_no;
708 function_t *probe, **prev;
709
710 /* Now insert it into the source file's list of
711 functions. Normally functions will be encountered in
712 ascending order, so a simple scan is quick. Note we're
713 building this list in reverse order. */
714 for (prev = &sources[src].functions;
715 (probe = *prev); prev = &probe->line_next)
716 if (probe->line <= line)
717 break;
718 fn->line_next = probe;
719 *prev = fn;
720
721 /* Mark last line in files touched by function. */
722 for (block_no = 0; block_no != fn->num_blocks; block_no++)
723 {
724 unsigned *enc = fn->blocks[block_no].u.line.encoding;
725 unsigned num = fn->blocks[block_no].u.line.num;
726
727 for (; num--; enc++)
728 if (!*enc)
729 {
730 if (enc[1] != src)
731 {
732 if (line >= sources[src].num_lines)
733 sources[src].num_lines = line + 1;
734 line = 0;
735 src = enc[1];
736 }
737 enc++;
738 num--;
739 }
740 else if (*enc > line)
741 line = *enc;
742 }
743 if (line >= sources[src].num_lines)
744 sources[src].num_lines = line + 1;
745
746 solve_flow_graph (fn);
747 if (fn->has_catch)
748 find_exception_blocks (fn);
749 *fn_end = fn;
750 fn_end = &fn->next;
751 }
752 else
753 /* The function was not in the executable -- some other
754 instance must have been selected. */
755 release_function (fn);
756 }
757 }
758
759 static void
output_gcov_file(const char * file_name,source_t * src)760 output_gcov_file (const char *file_name, source_t *src)
761 {
762 char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
763
764 if (src->coverage.lines)
765 {
766 FILE *gcov_file = fopen (gcov_file_name, "w");
767 if (gcov_file)
768 {
769 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
770
771 if (flag_intermediate_format)
772 output_intermediate_file (gcov_file, src);
773 else
774 output_lines (gcov_file, src);
775 if (ferror (gcov_file))
776 fnotice (stderr, "Error writing output file '%s'\n", gcov_file_name);
777 fclose (gcov_file);
778 }
779 else
780 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
781 }
782 else
783 {
784 unlink (gcov_file_name);
785 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
786 }
787 free (gcov_file_name);
788 }
789
790 static void
generate_results(const char * file_name)791 generate_results (const char *file_name)
792 {
793 unsigned ix;
794 source_t *src;
795 function_t *fn;
796
797 for (ix = n_sources, src = sources; ix--; src++)
798 if (src->num_lines)
799 src->lines = XCNEWVEC (line_t, src->num_lines);
800
801 for (fn = functions; fn; fn = fn->next)
802 {
803 coverage_t coverage;
804
805 memset (&coverage, 0, sizeof (coverage));
806 coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
807 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
808 if (flag_function_summary)
809 {
810 function_summary (&coverage, "Function");
811 fnotice (stdout, "\n");
812 }
813 }
814
815 if (file_name)
816 {
817 name_map_t *name_map = (name_map_t *)bsearch
818 (file_name, names, n_names, sizeof (*names), name_search);
819 if (name_map)
820 file_name = sources[name_map->src].coverage.name;
821 else
822 file_name = canonicalize_name (file_name);
823 }
824
825 for (ix = n_sources, src = sources; ix--; src++)
826 {
827 if (flag_relative_only)
828 {
829 /* Ignore this source, if it is an absolute path (after
830 source prefix removal). */
831 char first = src->coverage.name[0];
832
833 #if HAVE_DOS_BASED_FILE_SYSTEM
834 if (first && src->coverage.name[1] == ':')
835 first = src->coverage.name[2];
836 #endif
837 if (IS_DIR_SEPARATOR (first))
838 continue;
839 }
840
841 accumulate_line_counts (src);
842 function_summary (&src->coverage, "File");
843 total_lines += src->coverage.lines;
844 total_executed += src->coverage.lines_executed;
845 if (flag_gcov_file)
846 {
847 output_gcov_file (file_name, src);
848 fnotice (stdout, "\n");
849 }
850 }
851
852 if (!file_name)
853 executed_summary (total_lines, total_executed);
854 }
855
856 /* Release a function structure */
857
858 static void
release_function(function_t * fn)859 release_function (function_t *fn)
860 {
861 unsigned ix;
862 block_t *block;
863
864 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
865 {
866 arc_t *arc, *arc_n;
867
868 for (arc = block->succ; arc; arc = arc_n)
869 {
870 arc_n = arc->succ_next;
871 free (arc);
872 }
873 }
874 free (fn->blocks);
875 free (fn->counts);
876 if (flag_demangled_names && fn->demangled_name != fn->name)
877 free (fn->demangled_name);
878 free (fn->name);
879 }
880
881 /* Release all memory used. */
882
883 static void
release_structures(void)884 release_structures (void)
885 {
886 unsigned ix;
887 function_t *fn;
888
889 for (ix = n_sources; ix--;)
890 free (sources[ix].lines);
891 free (sources);
892
893 for (ix = n_names; ix--;)
894 free (names[ix].name);
895 free (names);
896
897 while ((fn = functions))
898 {
899 functions = fn->next;
900 release_function (fn);
901 }
902 }
903
904 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
905 is not specified, these are named from FILE_NAME sans extension. If
906 OBJECT_DIRECTORY is specified and is a directory, the files are in that
907 directory, but named from the basename of the FILE_NAME, sans extension.
908 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
909 and the data files are named from that. */
910
911 static void
create_file_names(const char * file_name)912 create_file_names (const char *file_name)
913 {
914 char *cptr;
915 char *name;
916 int length = strlen (file_name);
917 int base;
918
919 /* Free previous file names. */
920 free (bbg_file_name);
921 free (da_file_name);
922 da_file_name = bbg_file_name = NULL;
923 bbg_file_time = 0;
924 bbg_stamp = 0;
925
926 if (object_directory && object_directory[0])
927 {
928 struct stat status;
929
930 length += strlen (object_directory) + 2;
931 name = XNEWVEC (char, length);
932 name[0] = 0;
933
934 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
935 strcat (name, object_directory);
936 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
937 strcat (name, "/");
938 }
939 else
940 {
941 name = XNEWVEC (char, length + 1);
942 strcpy (name, file_name);
943 base = 0;
944 }
945
946 if (base)
947 {
948 /* Append source file name. */
949 const char *cptr = lbasename (file_name);
950 strcat (name, cptr ? cptr : file_name);
951 }
952
953 /* Remove the extension. */
954 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
955 if (cptr)
956 *cptr = 0;
957
958 length = strlen (name);
959
960 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
961 strcpy (bbg_file_name, name);
962 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
963
964 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
965 strcpy (da_file_name, name);
966 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
967
968 free (name);
969 return;
970 }
971
972 /* A is a string and B is a pointer to name_map_t. Compare for file
973 name orderability. */
974
975 static int
name_search(const void * a_,const void * b_)976 name_search (const void *a_, const void *b_)
977 {
978 const char *a = (const char *)a_;
979 const name_map_t *b = (const name_map_t *)b_;
980
981 #if HAVE_DOS_BASED_FILE_SYSTEM
982 return strcasecmp (a, b->name);
983 #else
984 return strcmp (a, b->name);
985 #endif
986 }
987
988 /* A and B are a pointer to name_map_t. Compare for file name
989 orderability. */
990
991 static int
name_sort(const void * a_,const void * b_)992 name_sort (const void *a_, const void *b_)
993 {
994 const name_map_t *a = (const name_map_t *)a_;
995 return name_search (a->name, b_);
996 }
997
998 /* Find or create a source file structure for FILE_NAME. Copies
999 FILE_NAME on creation */
1000
1001 static unsigned
find_source(const char * file_name)1002 find_source (const char *file_name)
1003 {
1004 name_map_t *name_map;
1005 char *canon;
1006 unsigned idx;
1007 struct stat status;
1008
1009 if (!file_name)
1010 file_name = "<unknown>";
1011 name_map = (name_map_t *)bsearch
1012 (file_name, names, n_names, sizeof (*names), name_search);
1013 if (name_map)
1014 {
1015 idx = name_map->src;
1016 goto check_date;
1017 }
1018
1019 if (n_names + 2 > a_names)
1020 {
1021 /* Extend the name map array -- we'll be inserting one or two
1022 entries. */
1023 a_names *= 2;
1024 name_map = XNEWVEC (name_map_t, a_names);
1025 memcpy (name_map, names, n_names * sizeof (*names));
1026 free (names);
1027 names = name_map;
1028 }
1029
1030 /* Not found, try the canonical name. */
1031 canon = canonicalize_name (file_name);
1032 name_map = (name_map_t *)bsearch
1033 (canon, names, n_names, sizeof (*names), name_search);
1034 if (!name_map)
1035 {
1036 /* Not found with canonical name, create a new source. */
1037 source_t *src;
1038
1039 if (n_sources == a_sources)
1040 {
1041 a_sources *= 2;
1042 src = XNEWVEC (source_t, a_sources);
1043 memcpy (src, sources, n_sources * sizeof (*sources));
1044 free (sources);
1045 sources = src;
1046 }
1047
1048 idx = n_sources;
1049
1050 name_map = &names[n_names++];
1051 name_map->name = canon;
1052 name_map->src = idx;
1053
1054 src = &sources[n_sources++];
1055 memset (src, 0, sizeof (*src));
1056 src->name = canon;
1057 src->coverage.name = src->name;
1058 if (source_length
1059 #if HAVE_DOS_BASED_FILE_SYSTEM
1060 /* You lose if separators don't match exactly in the
1061 prefix. */
1062 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1063 #else
1064 && !strncmp (source_prefix, src->coverage.name, source_length)
1065 #endif
1066 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1067 src->coverage.name += source_length + 1;
1068 if (!stat (src->name, &status))
1069 src->file_time = status.st_mtime;
1070 }
1071 else
1072 idx = name_map->src;
1073
1074 if (name_search (file_name, name_map))
1075 {
1076 /* Append the non-canonical name. */
1077 name_map = &names[n_names++];
1078 name_map->name = xstrdup (file_name);
1079 name_map->src = idx;
1080 }
1081
1082 /* Resort the name map. */
1083 qsort (names, n_names, sizeof (*names), name_sort);
1084
1085 check_date:
1086 if (sources[idx].file_time > bbg_file_time)
1087 {
1088 static int info_emitted;
1089
1090 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1091 file_name, bbg_file_name);
1092 if (!info_emitted)
1093 {
1094 fnotice (stderr,
1095 "(the message is displayed only once per source file)\n");
1096 info_emitted = 1;
1097 }
1098 sources[idx].file_time = 0;
1099 }
1100
1101 return idx;
1102 }
1103
1104 /* Read the notes file. Return list of functions read -- in reverse order. */
1105
1106 static function_t *
read_graph_file(void)1107 read_graph_file (void)
1108 {
1109 unsigned version;
1110 unsigned current_tag = 0;
1111 function_t *fn = NULL;
1112 function_t *fns = NULL;
1113 function_t **fns_end = &fns;
1114 unsigned src_idx = 0;
1115 unsigned ix;
1116 unsigned tag;
1117
1118 if (!gcov_open (bbg_file_name, 1))
1119 {
1120 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1121 return fns;
1122 }
1123 bbg_file_time = gcov_time ();
1124 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1125 {
1126 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1127 gcov_close ();
1128 return fns;
1129 }
1130
1131 version = gcov_read_unsigned ();
1132 if (version != GCOV_VERSION)
1133 {
1134 char v[4], e[4];
1135
1136 GCOV_UNSIGNED2STRING (v, version);
1137 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1138
1139 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1140 bbg_file_name, v, e);
1141 }
1142 bbg_stamp = gcov_read_unsigned ();
1143
1144 while ((tag = gcov_read_unsigned ()))
1145 {
1146 unsigned length = gcov_read_unsigned ();
1147 gcov_position_t base = gcov_position ();
1148
1149 if (tag == GCOV_TAG_FUNCTION)
1150 {
1151 char *function_name;
1152 unsigned ident, lineno;
1153 unsigned lineno_checksum, cfg_checksum;
1154
1155 ident = gcov_read_unsigned ();
1156 lineno_checksum = gcov_read_unsigned ();
1157 cfg_checksum = gcov_read_unsigned ();
1158 function_name = xstrdup (gcov_read_string ());
1159 src_idx = find_source (gcov_read_string ());
1160 lineno = gcov_read_unsigned ();
1161
1162 fn = XCNEW (function_t);
1163 fn->name = function_name;
1164 if (flag_demangled_names)
1165 {
1166 fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1167 if (!fn->demangled_name)
1168 fn->demangled_name = fn->name;
1169 }
1170 fn->ident = ident;
1171 fn->lineno_checksum = lineno_checksum;
1172 fn->cfg_checksum = cfg_checksum;
1173 fn->src = src_idx;
1174 fn->line = lineno;
1175
1176 fn->line_next = NULL;
1177 fn->next = NULL;
1178 *fns_end = fn;
1179 fns_end = &fn->next;
1180 current_tag = tag;
1181 }
1182 else if (fn && tag == GCOV_TAG_BLOCKS)
1183 {
1184 if (fn->blocks)
1185 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1186 bbg_file_name, fn->name);
1187 else
1188 {
1189 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
1190 fn->num_blocks = num_blocks;
1191
1192 fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
1193 for (ix = 0; ix != num_blocks; ix++)
1194 fn->blocks[ix].flags = gcov_read_unsigned ();
1195 }
1196 }
1197 else if (fn && tag == GCOV_TAG_ARCS)
1198 {
1199 unsigned src = gcov_read_unsigned ();
1200 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1201 block_t *src_blk = &fn->blocks[src];
1202 unsigned mark_catches = 0;
1203 struct arc_info *arc;
1204
1205 if (src >= fn->num_blocks || fn->blocks[src].succ)
1206 goto corrupt;
1207
1208 while (num_dests--)
1209 {
1210 unsigned dest = gcov_read_unsigned ();
1211 unsigned flags = gcov_read_unsigned ();
1212
1213 if (dest >= fn->num_blocks)
1214 goto corrupt;
1215 arc = XCNEW (arc_t);
1216
1217 arc->dst = &fn->blocks[dest];
1218 arc->src = src_blk;
1219
1220 arc->count = 0;
1221 arc->count_valid = 0;
1222 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1223 arc->fake = !!(flags & GCOV_ARC_FAKE);
1224 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1225
1226 arc->succ_next = src_blk->succ;
1227 src_blk->succ = arc;
1228 src_blk->num_succ++;
1229
1230 arc->pred_next = fn->blocks[dest].pred;
1231 fn->blocks[dest].pred = arc;
1232 fn->blocks[dest].num_pred++;
1233
1234 if (arc->fake)
1235 {
1236 if (src)
1237 {
1238 /* Exceptional exit from this function, the
1239 source block must be a call. */
1240 fn->blocks[src].is_call_site = 1;
1241 arc->is_call_non_return = 1;
1242 mark_catches = 1;
1243 }
1244 else
1245 {
1246 /* Non-local return from a callee of this
1247 function. The destination block is a setjmp. */
1248 arc->is_nonlocal_return = 1;
1249 fn->blocks[dest].is_nonlocal_return = 1;
1250 }
1251 }
1252
1253 if (!arc->on_tree)
1254 fn->num_counts++;
1255 }
1256
1257 if (mark_catches)
1258 {
1259 /* We have a fake exit from this block. The other
1260 non-fall through exits must be to catch handlers.
1261 Mark them as catch arcs. */
1262
1263 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1264 if (!arc->fake && !arc->fall_through)
1265 {
1266 arc->is_throw = 1;
1267 fn->has_catch = 1;
1268 }
1269 }
1270 }
1271 else if (fn && tag == GCOV_TAG_LINES)
1272 {
1273 unsigned blockno = gcov_read_unsigned ();
1274 unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
1275
1276 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
1277 goto corrupt;
1278
1279 for (ix = 0; ; )
1280 {
1281 unsigned lineno = gcov_read_unsigned ();
1282
1283 if (lineno)
1284 {
1285 if (!ix)
1286 {
1287 line_nos[ix++] = 0;
1288 line_nos[ix++] = src_idx;
1289 }
1290 line_nos[ix++] = lineno;
1291 }
1292 else
1293 {
1294 const char *file_name = gcov_read_string ();
1295
1296 if (!file_name)
1297 break;
1298 src_idx = find_source (file_name);
1299 line_nos[ix++] = 0;
1300 line_nos[ix++] = src_idx;
1301 }
1302 }
1303
1304 fn->blocks[blockno].u.line.encoding = line_nos;
1305 fn->blocks[blockno].u.line.num = ix;
1306 }
1307 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1308 {
1309 fn = NULL;
1310 current_tag = 0;
1311 }
1312 gcov_sync (base, length);
1313 if (gcov_is_error ())
1314 {
1315 corrupt:;
1316 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1317 break;
1318 }
1319 }
1320 gcov_close ();
1321
1322 if (!fns)
1323 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1324
1325 return fns;
1326 }
1327
1328 /* Reads profiles from the count file and attach to each
1329 function. Return nonzero if fatal error. */
1330
1331 static int
read_count_file(function_t * fns)1332 read_count_file (function_t *fns)
1333 {
1334 unsigned ix;
1335 unsigned version;
1336 unsigned tag;
1337 function_t *fn = NULL;
1338 int error = 0;
1339
1340 if (!gcov_open (da_file_name, 1))
1341 {
1342 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1343 da_file_name);
1344 no_data_file = 1;
1345 return 0;
1346 }
1347 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1348 {
1349 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1350 cleanup:;
1351 gcov_close ();
1352 return 1;
1353 }
1354 version = gcov_read_unsigned ();
1355 if (version != GCOV_VERSION)
1356 {
1357 char v[4], e[4];
1358
1359 GCOV_UNSIGNED2STRING (v, version);
1360 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1361
1362 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1363 da_file_name, v, e);
1364 }
1365 tag = gcov_read_unsigned ();
1366 if (tag != bbg_stamp)
1367 {
1368 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
1369 goto cleanup;
1370 }
1371
1372 while ((tag = gcov_read_unsigned ()))
1373 {
1374 unsigned length = gcov_read_unsigned ();
1375 unsigned long base = gcov_position ();
1376
1377 if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1378 {
1379 struct gcov_summary summary;
1380 gcov_read_summary (&summary);
1381 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1382 program_count++;
1383 }
1384 else if (tag == GCOV_TAG_FUNCTION && !length)
1385 ; /* placeholder */
1386 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1387 {
1388 unsigned ident;
1389 struct function_info *fn_n;
1390
1391 /* Try to find the function in the list. To speed up the
1392 search, first start from the last function found. */
1393 ident = gcov_read_unsigned ();
1394 fn_n = fns;
1395 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1396 {
1397 if (fn)
1398 ;
1399 else if ((fn = fn_n))
1400 fn_n = NULL;
1401 else
1402 {
1403 fnotice (stderr, "%s:unknown function '%u'\n",
1404 da_file_name, ident);
1405 break;
1406 }
1407 if (fn->ident == ident)
1408 break;
1409 }
1410
1411 if (!fn)
1412 ;
1413 else if (gcov_read_unsigned () != fn->lineno_checksum
1414 || gcov_read_unsigned () != fn->cfg_checksum)
1415 {
1416 mismatch:;
1417 fnotice (stderr, "%s:profile mismatch for '%s'\n",
1418 da_file_name, fn->name);
1419 goto cleanup;
1420 }
1421 }
1422 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1423 {
1424 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1425 goto mismatch;
1426
1427 if (!fn->counts)
1428 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1429
1430 for (ix = 0; ix != fn->num_counts; ix++)
1431 fn->counts[ix] += gcov_read_counter ();
1432 }
1433 gcov_sync (base, length);
1434 if ((error = gcov_is_error ()))
1435 {
1436 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1437 da_file_name);
1438 goto cleanup;
1439 }
1440 }
1441
1442 gcov_close ();
1443 return 0;
1444 }
1445
1446 /* Solve the flow graph. Propagate counts from the instrumented arcs
1447 to the blocks and the uninstrumented arcs. */
1448
1449 static void
solve_flow_graph(function_t * fn)1450 solve_flow_graph (function_t *fn)
1451 {
1452 unsigned ix;
1453 arc_t *arc;
1454 gcov_type *count_ptr = fn->counts;
1455 block_t *blk;
1456 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1457 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1458
1459 /* The arcs were built in reverse order. Fix that now. */
1460 for (ix = fn->num_blocks; ix--;)
1461 {
1462 arc_t *arc_p, *arc_n;
1463
1464 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1465 arc_p = arc, arc = arc_n)
1466 {
1467 arc_n = arc->succ_next;
1468 arc->succ_next = arc_p;
1469 }
1470 fn->blocks[ix].succ = arc_p;
1471
1472 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1473 arc_p = arc, arc = arc_n)
1474 {
1475 arc_n = arc->pred_next;
1476 arc->pred_next = arc_p;
1477 }
1478 fn->blocks[ix].pred = arc_p;
1479 }
1480
1481 if (fn->num_blocks < 2)
1482 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1483 bbg_file_name, fn->name);
1484 else
1485 {
1486 if (fn->blocks[ENTRY_BLOCK].num_pred)
1487 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1488 bbg_file_name, fn->name);
1489 else
1490 /* We can't deduce the entry block counts from the lack of
1491 predecessors. */
1492 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
1493
1494 if (fn->blocks[EXIT_BLOCK].num_succ)
1495 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1496 bbg_file_name, fn->name);
1497 else
1498 /* Likewise, we can't deduce exit block counts from the lack
1499 of its successors. */
1500 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
1501 }
1502
1503 /* Propagate the measured counts, this must be done in the same
1504 order as the code in profile.c */
1505 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1506 {
1507 block_t const *prev_dst = NULL;
1508 int out_of_order = 0;
1509 int non_fake_succ = 0;
1510
1511 for (arc = blk->succ; arc; arc = arc->succ_next)
1512 {
1513 if (!arc->fake)
1514 non_fake_succ++;
1515
1516 if (!arc->on_tree)
1517 {
1518 if (count_ptr)
1519 arc->count = *count_ptr++;
1520 arc->count_valid = 1;
1521 blk->num_succ--;
1522 arc->dst->num_pred--;
1523 }
1524 if (prev_dst && prev_dst > arc->dst)
1525 out_of_order = 1;
1526 prev_dst = arc->dst;
1527 }
1528 if (non_fake_succ == 1)
1529 {
1530 /* If there is only one non-fake exit, it is an
1531 unconditional branch. */
1532 for (arc = blk->succ; arc; arc = arc->succ_next)
1533 if (!arc->fake)
1534 {
1535 arc->is_unconditional = 1;
1536 /* If this block is instrumenting a call, it might be
1537 an artificial block. It is not artificial if it has
1538 a non-fallthrough exit, or the destination of this
1539 arc has more than one entry. Mark the destination
1540 block as a return site, if none of those conditions
1541 hold. */
1542 if (blk->is_call_site && arc->fall_through
1543 && arc->dst->pred == arc && !arc->pred_next)
1544 arc->dst->is_call_return = 1;
1545 }
1546 }
1547
1548 /* Sort the successor arcs into ascending dst order. profile.c
1549 normally produces arcs in the right order, but sometimes with
1550 one or two out of order. We're not using a particularly
1551 smart sort. */
1552 if (out_of_order)
1553 {
1554 arc_t *start = blk->succ;
1555 unsigned changes = 1;
1556
1557 while (changes)
1558 {
1559 arc_t *arc, *arc_p, *arc_n;
1560
1561 changes = 0;
1562 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1563 {
1564 if (arc->dst > arc_n->dst)
1565 {
1566 changes = 1;
1567 if (arc_p)
1568 arc_p->succ_next = arc_n;
1569 else
1570 start = arc_n;
1571 arc->succ_next = arc_n->succ_next;
1572 arc_n->succ_next = arc;
1573 arc_p = arc_n;
1574 }
1575 else
1576 {
1577 arc_p = arc;
1578 arc = arc_n;
1579 }
1580 }
1581 }
1582 blk->succ = start;
1583 }
1584
1585 /* Place it on the invalid chain, it will be ignored if that's
1586 wrong. */
1587 blk->invalid_chain = 1;
1588 blk->chain = invalid_blocks;
1589 invalid_blocks = blk;
1590 }
1591
1592 while (invalid_blocks || valid_blocks)
1593 {
1594 while ((blk = invalid_blocks))
1595 {
1596 gcov_type total = 0;
1597 const arc_t *arc;
1598
1599 invalid_blocks = blk->chain;
1600 blk->invalid_chain = 0;
1601 if (!blk->num_succ)
1602 for (arc = blk->succ; arc; arc = arc->succ_next)
1603 total += arc->count;
1604 else if (!blk->num_pred)
1605 for (arc = blk->pred; arc; arc = arc->pred_next)
1606 total += arc->count;
1607 else
1608 continue;
1609
1610 blk->count = total;
1611 blk->count_valid = 1;
1612 blk->chain = valid_blocks;
1613 blk->valid_chain = 1;
1614 valid_blocks = blk;
1615 }
1616 while ((blk = valid_blocks))
1617 {
1618 gcov_type total;
1619 arc_t *arc, *inv_arc;
1620
1621 valid_blocks = blk->chain;
1622 blk->valid_chain = 0;
1623 if (blk->num_succ == 1)
1624 {
1625 block_t *dst;
1626
1627 total = blk->count;
1628 inv_arc = NULL;
1629 for (arc = blk->succ; arc; arc = arc->succ_next)
1630 {
1631 total -= arc->count;
1632 if (!arc->count_valid)
1633 inv_arc = arc;
1634 }
1635 dst = inv_arc->dst;
1636 inv_arc->count_valid = 1;
1637 inv_arc->count = total;
1638 blk->num_succ--;
1639 dst->num_pred--;
1640 if (dst->count_valid)
1641 {
1642 if (dst->num_pred == 1 && !dst->valid_chain)
1643 {
1644 dst->chain = valid_blocks;
1645 dst->valid_chain = 1;
1646 valid_blocks = dst;
1647 }
1648 }
1649 else
1650 {
1651 if (!dst->num_pred && !dst->invalid_chain)
1652 {
1653 dst->chain = invalid_blocks;
1654 dst->invalid_chain = 1;
1655 invalid_blocks = dst;
1656 }
1657 }
1658 }
1659 if (blk->num_pred == 1)
1660 {
1661 block_t *src;
1662
1663 total = blk->count;
1664 inv_arc = NULL;
1665 for (arc = blk->pred; arc; arc = arc->pred_next)
1666 {
1667 total -= arc->count;
1668 if (!arc->count_valid)
1669 inv_arc = arc;
1670 }
1671 src = inv_arc->src;
1672 inv_arc->count_valid = 1;
1673 inv_arc->count = total;
1674 blk->num_pred--;
1675 src->num_succ--;
1676 if (src->count_valid)
1677 {
1678 if (src->num_succ == 1 && !src->valid_chain)
1679 {
1680 src->chain = valid_blocks;
1681 src->valid_chain = 1;
1682 valid_blocks = src;
1683 }
1684 }
1685 else
1686 {
1687 if (!src->num_succ && !src->invalid_chain)
1688 {
1689 src->chain = invalid_blocks;
1690 src->invalid_chain = 1;
1691 invalid_blocks = src;
1692 }
1693 }
1694 }
1695 }
1696 }
1697
1698 /* If the graph has been correctly solved, every block will have a
1699 valid count. */
1700 for (ix = 0; ix < fn->num_blocks; ix++)
1701 if (!fn->blocks[ix].count_valid)
1702 {
1703 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1704 bbg_file_name, fn->name);
1705 break;
1706 }
1707 }
1708
1709 /* Mark all the blocks only reachable via an incoming catch. */
1710
1711 static void
find_exception_blocks(function_t * fn)1712 find_exception_blocks (function_t *fn)
1713 {
1714 unsigned ix;
1715 block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks);
1716
1717 /* First mark all blocks as exceptional. */
1718 for (ix = fn->num_blocks; ix--;)
1719 fn->blocks[ix].exceptional = 1;
1720
1721 /* Now mark all the blocks reachable via non-fake edges */
1722 queue[0] = fn->blocks;
1723 queue[0]->exceptional = 0;
1724 for (ix = 1; ix;)
1725 {
1726 block_t *block = queue[--ix];
1727 const arc_t *arc;
1728
1729 for (arc = block->succ; arc; arc = arc->succ_next)
1730 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1731 {
1732 arc->dst->exceptional = 0;
1733 queue[ix++] = arc->dst;
1734 }
1735 }
1736 }
1737
1738
1739 /* Increment totals in COVERAGE according to arc ARC. */
1740
1741 static void
add_branch_counts(coverage_t * coverage,const arc_t * arc)1742 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1743 {
1744 if (arc->is_call_non_return)
1745 {
1746 coverage->calls++;
1747 if (arc->src->count)
1748 coverage->calls_executed++;
1749 }
1750 else if (!arc->is_unconditional)
1751 {
1752 coverage->branches++;
1753 if (arc->src->count)
1754 coverage->branches_executed++;
1755 if (arc->count)
1756 coverage->branches_taken++;
1757 }
1758 }
1759
1760 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1761 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1762 If DP is zero, no decimal point is printed. Only print 100% when
1763 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1764 format TOP. Return pointer to a static string. */
1765
1766 static char const *
format_gcov(gcov_type top,gcov_type bottom,int dp)1767 format_gcov (gcov_type top, gcov_type bottom, int dp)
1768 {
1769 static char buffer[20];
1770
1771 /* Handle invalid values that would result in a misleading value. */
1772 if (bottom != 0 && top > bottom && dp >= 0)
1773 {
1774 sprintf (buffer, "NAN %%");
1775 return buffer;
1776 }
1777
1778 if (dp >= 0)
1779 {
1780 float ratio = bottom ? (float)top / bottom : 0;
1781 int ix;
1782 unsigned limit = 100;
1783 unsigned percent;
1784
1785 for (ix = dp; ix--; )
1786 limit *= 10;
1787
1788 percent = (unsigned) (ratio * limit + (float)0.5);
1789 if (percent <= 0 && top)
1790 percent = 1;
1791 else if (percent >= limit && top != bottom)
1792 percent = limit - 1;
1793 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1794 if (dp)
1795 {
1796 dp++;
1797 do
1798 {
1799 buffer[ix+1] = buffer[ix];
1800 ix--;
1801 }
1802 while (dp--);
1803 buffer[ix + 1] = '.';
1804 }
1805 }
1806 else
1807 sprintf (buffer, "%" PRId64, (int64_t)top);
1808
1809 return buffer;
1810 }
1811
1812 /* Summary of execution */
1813
1814 static void
executed_summary(unsigned lines,unsigned executed)1815 executed_summary (unsigned lines, unsigned executed)
1816 {
1817 if (lines)
1818 fnotice (stdout, "Lines executed:%s of %d\n",
1819 format_gcov (executed, lines, 2), lines);
1820 else
1821 fnotice (stdout, "No executable lines\n");
1822 }
1823
1824 /* Output summary info for a function or file. */
1825
1826 static void
function_summary(const coverage_t * coverage,const char * title)1827 function_summary (const coverage_t *coverage, const char *title)
1828 {
1829 fnotice (stdout, "%s '%s'\n", title, coverage->name);
1830 executed_summary (coverage->lines, coverage->lines_executed);
1831
1832 if (flag_branches)
1833 {
1834 if (coverage->branches)
1835 {
1836 fnotice (stdout, "Branches executed:%s of %d\n",
1837 format_gcov (coverage->branches_executed,
1838 coverage->branches, 2),
1839 coverage->branches);
1840 fnotice (stdout, "Taken at least once:%s of %d\n",
1841 format_gcov (coverage->branches_taken,
1842 coverage->branches, 2),
1843 coverage->branches);
1844 }
1845 else
1846 fnotice (stdout, "No branches\n");
1847 if (coverage->calls)
1848 fnotice (stdout, "Calls executed:%s of %d\n",
1849 format_gcov (coverage->calls_executed, coverage->calls, 2),
1850 coverage->calls);
1851 else
1852 fnotice (stdout, "No calls\n");
1853 }
1854 }
1855
1856 /* Canonicalize the filename NAME by canonicalizing directory
1857 separators, eliding . components and resolving .. components
1858 appropriately. Always returns a unique string. */
1859
1860 static char *
canonicalize_name(const char * name)1861 canonicalize_name (const char *name)
1862 {
1863 /* The canonical name cannot be longer than the incoming name. */
1864 char *result = XNEWVEC (char, strlen (name) + 1);
1865 const char *base = name, *probe;
1866 char *ptr = result;
1867 char *dd_base;
1868 int slash = 0;
1869
1870 #if HAVE_DOS_BASED_FILE_SYSTEM
1871 if (base[0] && base[1] == ':')
1872 {
1873 result[0] = base[0];
1874 result[1] = ':';
1875 base += 2;
1876 ptr += 2;
1877 }
1878 #endif
1879 for (dd_base = ptr; *base; base = probe)
1880 {
1881 size_t len;
1882
1883 for (probe = base; *probe; probe++)
1884 if (IS_DIR_SEPARATOR (*probe))
1885 break;
1886
1887 len = probe - base;
1888 if (len == 1 && base[0] == '.')
1889 /* Elide a '.' directory */
1890 ;
1891 else if (len == 2 && base[0] == '.' && base[1] == '.')
1892 {
1893 /* '..', we can only elide it and the previous directory, if
1894 we're not a symlink. */
1895 struct stat ATTRIBUTE_UNUSED buf;
1896
1897 *ptr = 0;
1898 if (dd_base == ptr
1899 #if defined (S_ISLNK)
1900 /* S_ISLNK is not POSIX.1-1996. */
1901 || stat (result, &buf) || S_ISLNK (buf.st_mode)
1902 #endif
1903 )
1904 {
1905 /* Cannot elide, or unreadable or a symlink. */
1906 dd_base = ptr + 2 + slash;
1907 goto regular;
1908 }
1909 while (ptr != dd_base && *ptr != '/')
1910 ptr--;
1911 slash = ptr != result;
1912 }
1913 else
1914 {
1915 regular:
1916 /* Regular pathname component. */
1917 if (slash)
1918 *ptr++ = '/';
1919 memcpy (ptr, base, len);
1920 ptr += len;
1921 slash = 1;
1922 }
1923
1924 for (; IS_DIR_SEPARATOR (*probe); probe++)
1925 continue;
1926 }
1927 *ptr = 0;
1928
1929 return result;
1930 }
1931
1932 /* Generate an output file name. INPUT_NAME is the canonicalized main
1933 input file and SRC_NAME is the canonicalized file name.
1934 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
1935 long_output_names we prepend the processed name of the input file
1936 to each output name (except when the current source file is the
1937 input file, so you don't get a double concatenation). The two
1938 components are separated by '##'. With preserve_paths we create a
1939 filename from all path components of the source file, replacing '/'
1940 with '#', and .. with '^', without it we simply take the basename
1941 component. (Remember, the canonicalized name will already have
1942 elided '.' components and converted \\ separators.) */
1943
1944 static char *
make_gcov_file_name(const char * input_name,const char * src_name)1945 make_gcov_file_name (const char *input_name, const char *src_name)
1946 {
1947 char *ptr;
1948 char *result;
1949
1950 if (flag_long_names && input_name && strcmp (src_name, input_name))
1951 {
1952 /* Generate the input filename part. */
1953 result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
1954
1955 ptr = result;
1956 ptr = mangle_name (input_name, ptr);
1957 ptr[0] = ptr[1] = '#';
1958 ptr += 2;
1959 }
1960 else
1961 {
1962 result = XNEWVEC (char, strlen (src_name) + 10);
1963 ptr = result;
1964 }
1965
1966 ptr = mangle_name (src_name, ptr);
1967 strcpy (ptr, ".gcov");
1968
1969 return result;
1970 }
1971
1972 static char *
mangle_name(char const * base,char * ptr)1973 mangle_name (char const *base, char *ptr)
1974 {
1975 size_t len;
1976
1977 /* Generate the source filename part. */
1978 if (!flag_preserve_paths)
1979 {
1980 base = lbasename (base);
1981 len = strlen (base);
1982 memcpy (ptr, base, len);
1983 ptr += len;
1984 }
1985 else
1986 {
1987 /* Convert '/' to '#', convert '..' to '^',
1988 convert ':' to '~' on DOS based file system. */
1989 const char *probe;
1990
1991 #if HAVE_DOS_BASED_FILE_SYSTEM
1992 if (base[0] && base[1] == ':')
1993 {
1994 ptr[0] = base[0];
1995 ptr[1] = '~';
1996 ptr += 2;
1997 base += 2;
1998 }
1999 #endif
2000 for (; *base; base = probe)
2001 {
2002 size_t len;
2003
2004 for (probe = base; *probe; probe++)
2005 if (*probe == '/')
2006 break;
2007 len = probe - base;
2008 if (len == 2 && base[0] == '.' && base[1] == '.')
2009 *ptr++ = '^';
2010 else
2011 {
2012 memcpy (ptr, base, len);
2013 ptr += len;
2014 }
2015 if (*probe)
2016 {
2017 *ptr++ = '#';
2018 probe++;
2019 }
2020 }
2021 }
2022
2023 return ptr;
2024 }
2025
2026 /* Scan through the bb_data for each line in the block, increment
2027 the line number execution count indicated by the execution count of
2028 the appropriate basic block. */
2029
2030 static void
add_line_counts(coverage_t * coverage,function_t * fn)2031 add_line_counts (coverage_t *coverage, function_t *fn)
2032 {
2033 unsigned ix;
2034 line_t *line = NULL; /* This is propagated from one iteration to the
2035 next. */
2036
2037 /* Scan each basic block. */
2038 for (ix = 0; ix != fn->num_blocks; ix++)
2039 {
2040 block_t *block = &fn->blocks[ix];
2041 unsigned *encoding;
2042 const source_t *src = NULL;
2043 unsigned jx;
2044
2045 if (block->count && ix && ix + 1 != fn->num_blocks)
2046 fn->blocks_executed++;
2047 for (jx = 0, encoding = block->u.line.encoding;
2048 jx != block->u.line.num; jx++, encoding++)
2049 if (!*encoding)
2050 {
2051 src = &sources[*++encoding];
2052 jx++;
2053 }
2054 else
2055 {
2056 line = &src->lines[*encoding];
2057
2058 if (coverage)
2059 {
2060 if (!line->exists)
2061 coverage->lines++;
2062 if (!line->count && block->count)
2063 coverage->lines_executed++;
2064 }
2065 line->exists = 1;
2066 if (!block->exceptional)
2067 line->unexceptional = 1;
2068 line->count += block->count;
2069 }
2070 free (block->u.line.encoding);
2071 block->u.cycle.arc = NULL;
2072 block->u.cycle.ident = ~0U;
2073
2074 if (!ix || ix + 1 == fn->num_blocks)
2075 /* Entry or exit block */;
2076 else if (flag_all_blocks)
2077 {
2078 line_t *block_line = line;
2079
2080 if (!block_line)
2081 block_line = &sources[fn->src].lines[fn->line];
2082
2083 block->chain = block_line->u.blocks;
2084 block_line->u.blocks = block;
2085 }
2086 else if (flag_branches)
2087 {
2088 arc_t *arc;
2089
2090 for (arc = block->succ; arc; arc = arc->succ_next)
2091 {
2092 arc->line_next = line->u.branches;
2093 line->u.branches = arc;
2094 if (coverage && !arc->is_unconditional)
2095 add_branch_counts (coverage, arc);
2096 }
2097 }
2098 }
2099 if (!line)
2100 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2101 }
2102
2103 /* Accumulate the line counts of a file. */
2104
2105 static void
accumulate_line_counts(source_t * src)2106 accumulate_line_counts (source_t *src)
2107 {
2108 line_t *line;
2109 function_t *fn, *fn_p, *fn_n;
2110 unsigned ix;
2111
2112 /* Reverse the function order. */
2113 for (fn = src->functions, fn_p = NULL; fn;
2114 fn_p = fn, fn = fn_n)
2115 {
2116 fn_n = fn->line_next;
2117 fn->line_next = fn_p;
2118 }
2119 src->functions = fn_p;
2120
2121 for (ix = src->num_lines, line = src->lines; ix--; line++)
2122 {
2123 if (!flag_all_blocks)
2124 {
2125 arc_t *arc, *arc_p, *arc_n;
2126
2127 /* Total and reverse the branch information. */
2128 for (arc = line->u.branches, arc_p = NULL; arc;
2129 arc_p = arc, arc = arc_n)
2130 {
2131 arc_n = arc->line_next;
2132 arc->line_next = arc_p;
2133
2134 add_branch_counts (&src->coverage, arc);
2135 }
2136 line->u.branches = arc_p;
2137 }
2138 else if (line->u.blocks)
2139 {
2140 /* The user expects the line count to be the number of times
2141 a line has been executed. Simply summing the block count
2142 will give an artificially high number. The Right Thing
2143 is to sum the entry counts to the graph of blocks on this
2144 line, then find the elementary cycles of the local graph
2145 and add the transition counts of those cycles. */
2146 block_t *block, *block_p, *block_n;
2147 gcov_type count = 0;
2148
2149 /* Reverse the block information. */
2150 for (block = line->u.blocks, block_p = NULL; block;
2151 block_p = block, block = block_n)
2152 {
2153 block_n = block->chain;
2154 block->chain = block_p;
2155 block->u.cycle.ident = ix;
2156 }
2157 line->u.blocks = block_p;
2158
2159 /* Sum the entry arcs. */
2160 for (block = line->u.blocks; block; block = block->chain)
2161 {
2162 arc_t *arc;
2163
2164 for (arc = block->pred; arc; arc = arc->pred_next)
2165 {
2166 if (arc->src->u.cycle.ident != ix)
2167 count += arc->count;
2168 if (flag_branches)
2169 add_branch_counts (&src->coverage, arc);
2170 }
2171
2172 /* Initialize the cs_count. */
2173 for (arc = block->succ; arc; arc = arc->succ_next)
2174 arc->cs_count = arc->count;
2175 }
2176
2177 /* Find the loops. This uses the algorithm described in
2178 Tiernan 'An Efficient Search Algorithm to Find the
2179 Elementary Circuits of a Graph', CACM Dec 1970. We hold
2180 the P array by having each block point to the arc that
2181 connects to the previous block. The H array is implicitly
2182 held because of the arc ordering, and the block's
2183 previous arc pointer.
2184
2185 Although the algorithm is O(N^3) for highly connected
2186 graphs, at worst we'll have O(N^2), as most blocks have
2187 only one or two exits. Most graphs will be small.
2188
2189 For each loop we find, locate the arc with the smallest
2190 transition count, and add that to the cumulative
2191 count. Decrease flow over the cycle and remove the arc
2192 from consideration. */
2193 for (block = line->u.blocks; block; block = block->chain)
2194 {
2195 block_t *head = block;
2196 arc_t *arc;
2197
2198 next_vertex:;
2199 arc = head->succ;
2200 current_vertex:;
2201 while (arc)
2202 {
2203 block_t *dst = arc->dst;
2204 if (/* Already used that arc. */
2205 arc->cycle
2206 /* Not to same graph, or before first vertex. */
2207 || dst->u.cycle.ident != ix
2208 /* Already in path. */
2209 || dst->u.cycle.arc)
2210 {
2211 arc = arc->succ_next;
2212 continue;
2213 }
2214
2215 if (dst == block)
2216 {
2217 /* Found a closing arc. */
2218 gcov_type cycle_count = arc->cs_count;
2219 arc_t *cycle_arc = arc;
2220 arc_t *probe_arc;
2221
2222 /* Locate the smallest arc count of the loop. */
2223 for (dst = head; (probe_arc = dst->u.cycle.arc);
2224 dst = probe_arc->src)
2225 if (cycle_count > probe_arc->cs_count)
2226 {
2227 cycle_count = probe_arc->cs_count;
2228 cycle_arc = probe_arc;
2229 }
2230
2231 count += cycle_count;
2232 cycle_arc->cycle = 1;
2233
2234 /* Remove the flow from the cycle. */
2235 arc->cs_count -= cycle_count;
2236 for (dst = head; (probe_arc = dst->u.cycle.arc);
2237 dst = probe_arc->src)
2238 probe_arc->cs_count -= cycle_count;
2239
2240 /* Unwind to the cyclic arc. */
2241 while (head != cycle_arc->src)
2242 {
2243 arc = head->u.cycle.arc;
2244 head->u.cycle.arc = NULL;
2245 head = arc->src;
2246 }
2247 /* Move on. */
2248 arc = arc->succ_next;
2249 continue;
2250 }
2251
2252 /* Add new block to chain. */
2253 dst->u.cycle.arc = arc;
2254 head = dst;
2255 goto next_vertex;
2256 }
2257 /* We could not add another vertex to the path. Remove
2258 the last vertex from the list. */
2259 arc = head->u.cycle.arc;
2260 if (arc)
2261 {
2262 /* It was not the first vertex. Move onto next arc. */
2263 head->u.cycle.arc = NULL;
2264 head = arc->src;
2265 arc = arc->succ_next;
2266 goto current_vertex;
2267 }
2268 /* Mark this block as unusable. */
2269 block->u.cycle.ident = ~0U;
2270 }
2271
2272 line->count = count;
2273 }
2274
2275 if (line->exists)
2276 {
2277 src->coverage.lines++;
2278 if (line->count)
2279 src->coverage.lines_executed++;
2280 }
2281 }
2282 }
2283
2284 /* Output information about ARC number IX. Returns nonzero if
2285 anything is output. */
2286
2287 static int
output_branch_count(FILE * gcov_file,int ix,const arc_t * arc)2288 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
2289 {
2290 if (arc->is_call_non_return)
2291 {
2292 if (arc->src->count)
2293 {
2294 fnotice (gcov_file, "call %2d returned %s\n", ix,
2295 format_gcov (arc->src->count - arc->count,
2296 arc->src->count, -flag_counts));
2297 }
2298 else
2299 fnotice (gcov_file, "call %2d never executed\n", ix);
2300 }
2301 else if (!arc->is_unconditional)
2302 {
2303 if (arc->src->count)
2304 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
2305 format_gcov (arc->count, arc->src->count, -flag_counts),
2306 arc->fall_through ? " (fallthrough)"
2307 : arc->is_throw ? " (throw)" : "");
2308 else
2309 fnotice (gcov_file, "branch %2d never executed\n", ix);
2310 }
2311 else if (flag_unconditional && !arc->dst->is_call_return)
2312 {
2313 if (arc->src->count)
2314 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2315 format_gcov (arc->count, arc->src->count, -flag_counts));
2316 else
2317 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2318 }
2319 else
2320 return 0;
2321 return 1;
2322
2323 }
2324
2325 static const char *
read_line(FILE * file)2326 read_line (FILE *file)
2327 {
2328 static char *string;
2329 static size_t string_len;
2330 size_t pos = 0;
2331 char *ptr;
2332
2333 if (!string_len)
2334 {
2335 string_len = 200;
2336 string = XNEWVEC (char, string_len);
2337 }
2338
2339 while ((ptr = fgets (string + pos, string_len - pos, file)))
2340 {
2341 size_t len = strlen (string + pos);
2342
2343 if (string[pos + len - 1] == '\n')
2344 {
2345 string[pos + len - 1] = 0;
2346 return string;
2347 }
2348 pos += len;
2349 string = XRESIZEVEC (char, string, string_len * 2);
2350 string_len *= 2;
2351 }
2352
2353 return pos ? string : NULL;
2354 }
2355
2356 /* Read in the source file one line at a time, and output that line to
2357 the gcov file preceded by its execution count and other
2358 information. */
2359
2360 static void
output_lines(FILE * gcov_file,const source_t * src)2361 output_lines (FILE *gcov_file, const source_t *src)
2362 {
2363 FILE *source_file;
2364 unsigned line_num; /* current line number. */
2365 const line_t *line; /* current line info ptr. */
2366 const char *retval = ""; /* status of source file reading. */
2367 function_t *fn = NULL;
2368
2369 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name);
2370 if (!multiple_files)
2371 {
2372 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
2373 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
2374 no_data_file ? "-" : da_file_name);
2375 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs);
2376 }
2377 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
2378
2379 source_file = fopen (src->name, "r");
2380 if (!source_file)
2381 {
2382 fnotice (stderr, "Cannot open source file %s\n", src->name);
2383 retval = NULL;
2384 }
2385 else if (src->file_time == 0)
2386 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
2387
2388 if (flag_branches)
2389 fn = src->functions;
2390
2391 for (line_num = 1, line = &src->lines[line_num];
2392 line_num < src->num_lines; line_num++, line++)
2393 {
2394 for (; fn && fn->line == line_num; fn = fn->line_next)
2395 {
2396 arc_t *arc = fn->blocks[EXIT_BLOCK].pred;
2397 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2398 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2399
2400 for (; arc; arc = arc->pred_next)
2401 if (arc->fake)
2402 return_count -= arc->count;
2403
2404 fprintf (gcov_file, "function %s", flag_demangled_names ?
2405 fn->demangled_name : fn->name);
2406 fprintf (gcov_file, " called %s",
2407 format_gcov (called_count, 0, -1));
2408 fprintf (gcov_file, " returned %s",
2409 format_gcov (return_count, called_count, 0));
2410 fprintf (gcov_file, " blocks executed %s",
2411 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
2412 fprintf (gcov_file, "\n");
2413 }
2414
2415 if (retval)
2416 retval = read_line (source_file);
2417
2418 /* For lines which don't exist in the .bb file, print '-' before
2419 the source line. For lines which exist but were never
2420 executed, print '#####' or '=====' before the source line.
2421 Otherwise, print the execution count before the source line.
2422 There are 16 spaces of indentation added before the source
2423 line so that tabs won't be messed up. */
2424 fprintf (gcov_file, "%9s:%5u:%s\n",
2425 !line->exists ? "-" : line->count
2426 ? format_gcov (line->count, 0, -1)
2427 : line->unexceptional ? "#####" : "=====", line_num,
2428 retval ? retval : "/*EOF*/");
2429
2430 if (flag_all_blocks)
2431 {
2432 block_t *block;
2433 arc_t *arc;
2434 int ix, jx;
2435
2436 for (ix = jx = 0, block = line->u.blocks; block;
2437 block = block->chain)
2438 {
2439 if (!block->is_call_return)
2440 fprintf (gcov_file, "%9s:%5u-block %2d\n",
2441 !line->exists ? "-" : block->count
2442 ? format_gcov (block->count, 0, -1)
2443 : block->exceptional ? "%%%%%" : "$$$$$",
2444 line_num, ix++);
2445 if (flag_branches)
2446 for (arc = block->succ; arc; arc = arc->succ_next)
2447 jx += output_branch_count (gcov_file, jx, arc);
2448 }
2449 }
2450 else if (flag_branches)
2451 {
2452 int ix;
2453 arc_t *arc;
2454
2455 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2456 ix += output_branch_count (gcov_file, ix, arc);
2457 }
2458 }
2459
2460 /* Handle all remaining source lines. There may be lines after the
2461 last line of code. */
2462 if (retval)
2463 {
2464 for (; (retval = read_line (source_file)); line_num++)
2465 fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
2466 }
2467
2468 if (source_file)
2469 fclose (source_file);
2470 }
2471