Mercurial > hg > CbC > CbC_gcc
comparison gcc/gcov.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 3bfb6c00c1e0 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* Gcov.c: prepend line execution counts and branch probabilities to a | |
2 source file. | |
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, | |
4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | |
5 Free Software Foundation, Inc. | |
6 Contributed by James E. Wilson of Cygnus Support. | |
7 Mangled by Bob Manson of Cygnus Support. | |
8 Mangled further by Nathan Sidwell <nathan@codesourcery.com> | |
9 | |
10 Gcov is free software; you can redistribute it and/or modify | |
11 it under the terms of the GNU General Public License as published by | |
12 the Free Software Foundation; either version 3, or (at your option) | |
13 any later version. | |
14 | |
15 Gcov is distributed in the hope that it will be useful, | |
16 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 GNU General Public License for more details. | |
19 | |
20 You should have received a copy of the GNU General Public License | |
21 along with Gcov; see the file COPYING3. If not see | |
22 <http://www.gnu.org/licenses/>. */ | |
23 | |
24 /* ??? Print a list of the ten blocks with the highest execution counts, | |
25 and list the line numbers corresponding to those blocks. Also, perhaps | |
26 list the line numbers with the highest execution counts, only printing | |
27 the first if there are several which are all listed in the same block. */ | |
28 | |
29 /* ??? Should have an option to print the number of basic blocks, and the | |
30 percent of them that are covered. */ | |
31 | |
32 /* Need an option to show individual block counts, and show | |
33 probabilities of fall through arcs. */ | |
34 | |
35 #include "config.h" | |
36 #include "system.h" | |
37 #include "coretypes.h" | |
38 #include "tm.h" | |
39 #include "intl.h" | |
40 #include "version.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 /* This is the size of the buffer used to read in source file lines. */ | |
58 | |
59 #define STRING_SIZE 200 | |
60 | |
61 struct function_info; | |
62 struct block_info; | |
63 struct source_info; | |
64 | |
65 /* Describes an arc between two basic blocks. */ | |
66 | |
67 typedef struct arc_info | |
68 { | |
69 /* source and destination blocks. */ | |
70 struct block_info *src; | |
71 struct block_info *dst; | |
72 | |
73 /* transition counts. */ | |
74 gcov_type count; | |
75 /* used in cycle search, so that we do not clobber original counts. */ | |
76 gcov_type cs_count; | |
77 | |
78 unsigned int count_valid : 1; | |
79 unsigned int on_tree : 1; | |
80 unsigned int fake : 1; | |
81 unsigned int fall_through : 1; | |
82 | |
83 /* Arc is for a function that abnormally returns. */ | |
84 unsigned int is_call_non_return : 1; | |
85 | |
86 /* Arc is for catch/setjmp. */ | |
87 unsigned int is_nonlocal_return : 1; | |
88 | |
89 /* Is an unconditional branch. */ | |
90 unsigned int is_unconditional : 1; | |
91 | |
92 /* Loop making arc. */ | |
93 unsigned int cycle : 1; | |
94 | |
95 /* Next branch on line. */ | |
96 struct arc_info *line_next; | |
97 | |
98 /* Links to next arc on src and dst lists. */ | |
99 struct arc_info *succ_next; | |
100 struct arc_info *pred_next; | |
101 } arc_t; | |
102 | |
103 /* Describes a basic block. Contains lists of arcs to successor and | |
104 predecessor blocks. */ | |
105 | |
106 typedef struct block_info | |
107 { | |
108 /* Chain of exit and entry arcs. */ | |
109 arc_t *succ; | |
110 arc_t *pred; | |
111 | |
112 /* Number of unprocessed exit and entry arcs. */ | |
113 gcov_type num_succ; | |
114 gcov_type num_pred; | |
115 | |
116 /* Block execution count. */ | |
117 gcov_type count; | |
118 unsigned flags : 13; | |
119 unsigned count_valid : 1; | |
120 unsigned valid_chain : 1; | |
121 unsigned invalid_chain : 1; | |
122 | |
123 /* Block is a call instrumenting site. */ | |
124 unsigned is_call_site : 1; /* Does the call. */ | |
125 unsigned is_call_return : 1; /* Is the return. */ | |
126 | |
127 /* Block is a landing pad for longjmp or throw. */ | |
128 unsigned is_nonlocal_return : 1; | |
129 | |
130 union | |
131 { | |
132 struct | |
133 { | |
134 /* Array of line numbers and source files. source files are | |
135 introduced by a linenumber of zero, the next 'line number' is | |
136 the number of the source file. Always starts with a source | |
137 file. */ | |
138 unsigned *encoding; | |
139 unsigned num; | |
140 } line; /* Valid until blocks are linked onto lines */ | |
141 struct | |
142 { | |
143 /* Single line graph cycle workspace. Used for all-blocks | |
144 mode. */ | |
145 arc_t *arc; | |
146 unsigned ident; | |
147 } cycle; /* Used in all-blocks mode, after blocks are linked onto | |
148 lines. */ | |
149 } u; | |
150 | |
151 /* Temporary chain for solving graph, and for chaining blocks on one | |
152 line. */ | |
153 struct block_info *chain; | |
154 | |
155 } block_t; | |
156 | |
157 /* Describes a single function. Contains an array of basic blocks. */ | |
158 | |
159 typedef struct function_info | |
160 { | |
161 /* Name of function. */ | |
162 char *name; | |
163 unsigned ident; | |
164 unsigned checksum; | |
165 | |
166 /* Array of basic blocks. */ | |
167 block_t *blocks; | |
168 unsigned num_blocks; | |
169 unsigned blocks_executed; | |
170 | |
171 /* Raw arc coverage counts. */ | |
172 gcov_type *counts; | |
173 unsigned num_counts; | |
174 | |
175 /* First line number. */ | |
176 unsigned line; | |
177 struct source_info *src; | |
178 | |
179 /* Next function in same source file. */ | |
180 struct function_info *line_next; | |
181 | |
182 /* Next function. */ | |
183 struct function_info *next; | |
184 } function_t; | |
185 | |
186 /* Describes coverage of a file or function. */ | |
187 | |
188 typedef struct coverage_info | |
189 { | |
190 int lines; | |
191 int lines_executed; | |
192 | |
193 int branches; | |
194 int branches_executed; | |
195 int branches_taken; | |
196 | |
197 int calls; | |
198 int calls_executed; | |
199 | |
200 char *name; | |
201 } coverage_t; | |
202 | |
203 /* Describes a single line of source. Contains a chain of basic blocks | |
204 with code on it. */ | |
205 | |
206 typedef struct line_info | |
207 { | |
208 gcov_type count; /* execution count */ | |
209 union | |
210 { | |
211 arc_t *branches; /* branches from blocks that end on this | |
212 line. Used for branch-counts when not | |
213 all-blocks mode. */ | |
214 block_t *blocks; /* blocks which start on this line. Used | |
215 in all-blocks mode. */ | |
216 } u; | |
217 unsigned exists : 1; | |
218 } line_t; | |
219 | |
220 /* Describes a file mentioned in the block graph. Contains an array | |
221 of line info. */ | |
222 | |
223 typedef struct source_info | |
224 { | |
225 /* Name of source file. */ | |
226 char *name; | |
227 unsigned index; | |
228 time_t file_time; | |
229 | |
230 /* Array of line information. */ | |
231 line_t *lines; | |
232 unsigned num_lines; | |
233 | |
234 coverage_t coverage; | |
235 | |
236 /* Functions in this source file. These are in ascending line | |
237 number order. */ | |
238 function_t *functions; | |
239 | |
240 /* Next source file. */ | |
241 struct source_info *next; | |
242 } source_t; | |
243 | |
244 /* Holds a list of function basic block graphs. */ | |
245 | |
246 static function_t *functions; | |
247 | |
248 /* This points to the head of the sourcefile structure list. New elements | |
249 are always prepended. */ | |
250 | |
251 static source_t *sources; | |
252 | |
253 /* Next index for a source file. */ | |
254 | |
255 static unsigned source_index; | |
256 | |
257 /* This holds data summary information. */ | |
258 | |
259 static struct gcov_summary object_summary; | |
260 static unsigned program_count; | |
261 | |
262 /* Modification time of graph file. */ | |
263 | |
264 static time_t bbg_file_time; | |
265 | |
266 /* Name and file pointer of the input file for the basic block graph. */ | |
267 | |
268 static char *bbg_file_name; | |
269 | |
270 /* Stamp of the bbg file */ | |
271 static unsigned bbg_stamp; | |
272 | |
273 /* Name and file pointer of the input file for the arc count data. */ | |
274 | |
275 static char *da_file_name; | |
276 | |
277 /* Data file is missing. */ | |
278 | |
279 static int no_data_file; | |
280 | |
281 /* If there is several input files, compute and display results after | |
282 reading all data files. This way if two or more gcda file refer to | |
283 the same source file (eg inline subprograms in a .h file), the | |
284 counts are added. */ | |
285 | |
286 static int multiple_files = 0; | |
287 | |
288 /* Output branch probabilities. */ | |
289 | |
290 static int flag_branches = 0; | |
291 | |
292 /* Show unconditional branches too. */ | |
293 static int flag_unconditional = 0; | |
294 | |
295 /* Output a gcov file if this is true. This is on by default, and can | |
296 be turned off by the -n option. */ | |
297 | |
298 static int flag_gcov_file = 1; | |
299 | |
300 /* For included files, make the gcov output file name include the name | |
301 of the input source file. For example, if x.h is included in a.c, | |
302 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ | |
303 | |
304 static int flag_long_names = 0; | |
305 | |
306 /* Output count information for every basic block, not merely those | |
307 that contain line number information. */ | |
308 | |
309 static int flag_all_blocks = 0; | |
310 | |
311 /* Output summary info for each function. */ | |
312 | |
313 static int flag_function_summary = 0; | |
314 | |
315 /* Object directory file prefix. This is the directory/file where the | |
316 graph and data files are looked for, if nonzero. */ | |
317 | |
318 static char *object_directory = 0; | |
319 | |
320 /* Preserve all pathname components. Needed when object files and | |
321 source files are in subdirectories. '/' is mangled as '#', '.' is | |
322 elided and '..' mangled to '^'. */ | |
323 | |
324 static int flag_preserve_paths = 0; | |
325 | |
326 /* Output the number of times a branch was taken as opposed to the percentage | |
327 of times it was taken. */ | |
328 | |
329 static int flag_counts = 0; | |
330 | |
331 /* Forward declarations. */ | |
332 static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; | |
333 static int process_args (int, char **); | |
334 static void print_usage (int) ATTRIBUTE_NORETURN; | |
335 static void print_version (void) ATTRIBUTE_NORETURN; | |
336 static void process_file (const char *); | |
337 static void generate_results (const char *); | |
338 static void create_file_names (const char *); | |
339 static source_t *find_source (const char *); | |
340 static int read_graph_file (void); | |
341 static int read_count_file (void); | |
342 static void solve_flow_graph (function_t *); | |
343 static void add_branch_counts (coverage_t *, const arc_t *); | |
344 static void add_line_counts (coverage_t *, function_t *); | |
345 static void function_summary (const coverage_t *, const char *); | |
346 static const char *format_gcov (gcov_type, gcov_type, int); | |
347 static void accumulate_line_counts (source_t *); | |
348 static int output_branch_count (FILE *, int, const arc_t *); | |
349 static void output_lines (FILE *, const source_t *); | |
350 static char *make_gcov_file_name (const char *, const char *); | |
351 static void release_structures (void); | |
352 extern int main (int, char **); | |
353 | |
354 int | |
355 main (int argc, char **argv) | |
356 { | |
357 int argno; | |
358 | |
359 /* Unlock the stdio streams. */ | |
360 unlock_std_streams (); | |
361 | |
362 gcc_init_libintl (); | |
363 | |
364 /* Handle response files. */ | |
365 expandargv (&argc, &argv); | |
366 | |
367 argno = process_args (argc, argv); | |
368 if (optind == argc) | |
369 print_usage (true); | |
370 | |
371 if (argc - argno > 1) | |
372 multiple_files = 1; | |
373 | |
374 for (; argno != argc; argno++) | |
375 process_file (argv[argno]); | |
376 | |
377 generate_results (multiple_files ? NULL : argv[argc - 1]); | |
378 | |
379 release_structures (); | |
380 | |
381 return 0; | |
382 } | |
383 | |
384 static void | |
385 fnotice (FILE *file, const char *cmsgid, ...) | |
386 { | |
387 va_list ap; | |
388 | |
389 va_start (ap, cmsgid); | |
390 vfprintf (file, _(cmsgid), ap); | |
391 va_end (ap); | |
392 } | |
393 | |
394 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, | |
395 otherwise the output of --help. */ | |
396 | |
397 static void | |
398 print_usage (int error_p) | |
399 { | |
400 FILE *file = error_p ? stderr : stdout; | |
401 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; | |
402 | |
403 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE...\n\n"); | |
404 fnotice (file, "Print code coverage information.\n\n"); | |
405 fnotice (file, " -h, --help Print this help, then exit\n"); | |
406 fnotice (file, " -v, --version Print version number, then exit\n"); | |
407 fnotice (file, " -a, --all-blocks Show information for every basic block\n"); | |
408 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n"); | |
409 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\ | |
410 rather than percentages\n"); | |
411 fnotice (file, " -n, --no-output Do not create an output file\n"); | |
412 fnotice (file, " -l, --long-file-names Use long output file names for included\n\ | |
413 source files\n"); | |
414 fnotice (file, " -f, --function-summaries Output summaries for each function\n"); | |
415 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); | |
416 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); | |
417 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); | |
418 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", | |
419 bug_report_url); | |
420 exit (status); | |
421 } | |
422 | |
423 /* Print version information and exit. */ | |
424 | |
425 static void | |
426 print_version (void) | |
427 { | |
428 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string); | |
429 fprintf (stdout, "Copyright %s 2009 Free Software Foundation, Inc.\n", | |
430 _("(C)")); | |
431 fnotice (stdout, | |
432 _("This is free software; see the source for copying conditions.\n" | |
433 "There is NO warranty; not even for MERCHANTABILITY or \n" | |
434 "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); | |
435 exit (SUCCESS_EXIT_CODE); | |
436 } | |
437 | |
438 static const struct option options[] = | |
439 { | |
440 { "help", no_argument, NULL, 'h' }, | |
441 { "version", no_argument, NULL, 'v' }, | |
442 { "all-blocks", no_argument, NULL, 'a' }, | |
443 { "branch-probabilities", no_argument, NULL, 'b' }, | |
444 { "branch-counts", no_argument, NULL, 'c' }, | |
445 { "no-output", no_argument, NULL, 'n' }, | |
446 { "long-file-names", no_argument, NULL, 'l' }, | |
447 { "function-summaries", no_argument, NULL, 'f' }, | |
448 { "preserve-paths", no_argument, NULL, 'p' }, | |
449 { "object-directory", required_argument, NULL, 'o' }, | |
450 { "object-file", required_argument, NULL, 'o' }, | |
451 { "unconditional-branches", no_argument, NULL, 'u' }, | |
452 { 0, 0, 0, 0 } | |
453 }; | |
454 | |
455 /* Process args, return index to first non-arg. */ | |
456 | |
457 static int | |
458 process_args (int argc, char **argv) | |
459 { | |
460 int opt; | |
461 | |
462 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1) | |
463 { | |
464 switch (opt) | |
465 { | |
466 case 'a': | |
467 flag_all_blocks = 1; | |
468 break; | |
469 case 'b': | |
470 flag_branches = 1; | |
471 break; | |
472 case 'c': | |
473 flag_counts = 1; | |
474 break; | |
475 case 'f': | |
476 flag_function_summary = 1; | |
477 break; | |
478 case 'h': | |
479 print_usage (false); | |
480 /* print_usage will exit. */ | |
481 case 'l': | |
482 flag_long_names = 1; | |
483 break; | |
484 case 'n': | |
485 flag_gcov_file = 0; | |
486 break; | |
487 case 'o': | |
488 object_directory = optarg; | |
489 break; | |
490 case 'p': | |
491 flag_preserve_paths = 1; | |
492 break; | |
493 case 'u': | |
494 flag_unconditional = 1; | |
495 break; | |
496 case 'v': | |
497 print_version (); | |
498 /* print_version will exit. */ | |
499 default: | |
500 print_usage (true); | |
501 /* print_usage will exit. */ | |
502 } | |
503 } | |
504 | |
505 return optind; | |
506 } | |
507 | |
508 /* Process a single source file. */ | |
509 | |
510 static void | |
511 process_file (const char *file_name) | |
512 { | |
513 function_t *fn; | |
514 function_t *fn_p; | |
515 function_t *old_functions; | |
516 | |
517 /* Save and clear the list of current functions. They will be appended | |
518 later. */ | |
519 old_functions = functions; | |
520 functions = NULL; | |
521 | |
522 create_file_names (file_name); | |
523 if (read_graph_file ()) | |
524 return; | |
525 | |
526 if (!functions) | |
527 { | |
528 fnotice (stderr, "%s:no functions found\n", bbg_file_name); | |
529 return; | |
530 } | |
531 | |
532 if (read_count_file ()) | |
533 return; | |
534 | |
535 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next) | |
536 solve_flow_graph (fn); | |
537 | |
538 if (fn_p) | |
539 fn_p->next = old_functions; | |
540 } | |
541 | |
542 static void | |
543 generate_results (const char *file_name) | |
544 { | |
545 source_t *src; | |
546 function_t *fn; | |
547 | |
548 for (src = sources; src; src = src->next) | |
549 src->lines = XCNEWVEC (line_t, src->num_lines); | |
550 for (fn = functions; fn; fn = fn->next) | |
551 { | |
552 coverage_t coverage; | |
553 | |
554 memset (&coverage, 0, sizeof (coverage)); | |
555 coverage.name = fn->name; | |
556 add_line_counts (flag_function_summary ? &coverage : NULL, fn); | |
557 if (flag_function_summary) | |
558 { | |
559 function_summary (&coverage, "Function"); | |
560 fnotice (stdout, "\n"); | |
561 } | |
562 } | |
563 | |
564 for (src = sources; src; src = src->next) | |
565 { | |
566 accumulate_line_counts (src); | |
567 function_summary (&src->coverage, "File"); | |
568 if (flag_gcov_file) | |
569 { | |
570 char *gcov_file_name = make_gcov_file_name (file_name, src->name); | |
571 FILE *gcov_file = fopen (gcov_file_name, "w"); | |
572 | |
573 if (gcov_file) | |
574 { | |
575 fnotice (stdout, "%s:creating '%s'\n", | |
576 src->name, gcov_file_name); | |
577 output_lines (gcov_file, src); | |
578 if (ferror (gcov_file)) | |
579 fnotice (stderr, "%s:error writing output file '%s'\n", | |
580 src->name, gcov_file_name); | |
581 fclose (gcov_file); | |
582 } | |
583 else | |
584 fnotice (stderr, "%s:could not open output file '%s'\n", | |
585 src->name, gcov_file_name); | |
586 free (gcov_file_name); | |
587 } | |
588 fnotice (stdout, "\n"); | |
589 } | |
590 } | |
591 | |
592 /* Release all memory used. */ | |
593 | |
594 static void | |
595 release_structures (void) | |
596 { | |
597 function_t *fn; | |
598 source_t *src; | |
599 | |
600 while ((src = sources)) | |
601 { | |
602 sources = src->next; | |
603 | |
604 free (src->name); | |
605 free (src->lines); | |
606 } | |
607 | |
608 while ((fn = functions)) | |
609 { | |
610 unsigned ix; | |
611 block_t *block; | |
612 | |
613 functions = fn->next; | |
614 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++) | |
615 { | |
616 arc_t *arc, *arc_n; | |
617 | |
618 for (arc = block->succ; arc; arc = arc_n) | |
619 { | |
620 arc_n = arc->succ_next; | |
621 free (arc); | |
622 } | |
623 } | |
624 free (fn->blocks); | |
625 free (fn->counts); | |
626 } | |
627 } | |
628 | |
629 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY | |
630 is not specified, these are looked for in the current directory, | |
631 and named from the basename of the FILE_NAME sans extension. If | |
632 OBJECT_DIRECTORY is specified and is a directory, the files are in | |
633 that directory, but named from the basename of the FILE_NAME, sans | |
634 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of | |
635 the object *file*, and the data files are named from that. */ | |
636 | |
637 static void | |
638 create_file_names (const char *file_name) | |
639 { | |
640 char *cptr; | |
641 char *name; | |
642 int length = strlen (file_name); | |
643 int base; | |
644 | |
645 /* Free previous file names. */ | |
646 if (bbg_file_name) | |
647 free (bbg_file_name); | |
648 if (da_file_name) | |
649 free (da_file_name); | |
650 da_file_name = bbg_file_name = NULL; | |
651 bbg_file_time = 0; | |
652 bbg_stamp = 0; | |
653 | |
654 if (object_directory && object_directory[0]) | |
655 { | |
656 struct stat status; | |
657 | |
658 length += strlen (object_directory) + 2; | |
659 name = XNEWVEC (char, length); | |
660 name[0] = 0; | |
661 | |
662 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); | |
663 strcat (name, object_directory); | |
664 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1]))) | |
665 strcat (name, "/"); | |
666 } | |
667 else | |
668 { | |
669 name = XNEWVEC (char, length + 1); | |
670 name[0] = 0; | |
671 base = 1; | |
672 } | |
673 | |
674 if (base) | |
675 { | |
676 /* Append source file name. */ | |
677 const char *cptr = lbasename (file_name); | |
678 strcat (name, cptr ? cptr : file_name); | |
679 } | |
680 | |
681 /* Remove the extension. */ | |
682 cptr = strrchr (name, '.'); | |
683 if (cptr) | |
684 *cptr = 0; | |
685 | |
686 length = strlen (name); | |
687 | |
688 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1); | |
689 strcpy (bbg_file_name, name); | |
690 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); | |
691 | |
692 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1); | |
693 strcpy (da_file_name, name); | |
694 strcpy (da_file_name + length, GCOV_DATA_SUFFIX); | |
695 | |
696 free (name); | |
697 return; | |
698 } | |
699 | |
700 /* Find or create a source file structure for FILE_NAME. Copies | |
701 FILE_NAME on creation */ | |
702 | |
703 static source_t * | |
704 find_source (const char *file_name) | |
705 { | |
706 source_t *src; | |
707 struct stat status; | |
708 | |
709 if (!file_name) | |
710 file_name = "<unknown>"; | |
711 | |
712 for (src = sources; src; src = src->next) | |
713 if (!strcmp (file_name, src->name)) | |
714 break; | |
715 | |
716 if (!src) | |
717 { | |
718 src = XCNEW (source_t); | |
719 src->name = xstrdup (file_name); | |
720 src->coverage.name = src->name; | |
721 src->index = source_index++; | |
722 src->next = sources; | |
723 sources = src; | |
724 | |
725 if (!stat (file_name, &status)) | |
726 src->file_time = status.st_mtime; | |
727 } | |
728 | |
729 if (src->file_time > bbg_file_time) | |
730 { | |
731 static int info_emitted; | |
732 | |
733 fnotice (stderr, "%s:source file is newer than graph file '%s'\n", | |
734 src->name, bbg_file_name); | |
735 if (!info_emitted) | |
736 { | |
737 fnotice (stderr, | |
738 "(the message is only displayed one per source file)\n"); | |
739 info_emitted = 1; | |
740 } | |
741 src->file_time = 0; | |
742 } | |
743 | |
744 return src; | |
745 } | |
746 | |
747 /* Read the graph file. Return nonzero on fatal error. */ | |
748 | |
749 static int | |
750 read_graph_file (void) | |
751 { | |
752 unsigned version; | |
753 unsigned current_tag = 0; | |
754 struct function_info *fn = NULL; | |
755 function_t *old_functions_head = functions; | |
756 source_t *src = NULL; | |
757 unsigned ix; | |
758 unsigned tag; | |
759 | |
760 if (!gcov_open (bbg_file_name, 1)) | |
761 { | |
762 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name); | |
763 return 1; | |
764 } | |
765 bbg_file_time = gcov_time (); | |
766 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) | |
767 { | |
768 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name); | |
769 gcov_close (); | |
770 return 1; | |
771 } | |
772 | |
773 version = gcov_read_unsigned (); | |
774 if (version != GCOV_VERSION) | |
775 { | |
776 char v[4], e[4]; | |
777 | |
778 GCOV_UNSIGNED2STRING (v, version); | |
779 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); | |
780 | |
781 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n", | |
782 bbg_file_name, v, e); | |
783 } | |
784 bbg_stamp = gcov_read_unsigned (); | |
785 | |
786 while ((tag = gcov_read_unsigned ())) | |
787 { | |
788 unsigned length = gcov_read_unsigned (); | |
789 gcov_position_t base = gcov_position (); | |
790 | |
791 if (tag == GCOV_TAG_FUNCTION) | |
792 { | |
793 char *function_name; | |
794 unsigned ident, checksum, lineno; | |
795 source_t *src; | |
796 function_t *probe, *prev; | |
797 | |
798 ident = gcov_read_unsigned (); | |
799 checksum = gcov_read_unsigned (); | |
800 function_name = xstrdup (gcov_read_string ()); | |
801 src = find_source (gcov_read_string ()); | |
802 lineno = gcov_read_unsigned (); | |
803 | |
804 fn = XCNEW (function_t); | |
805 fn->name = function_name; | |
806 fn->ident = ident; | |
807 fn->checksum = checksum; | |
808 fn->src = src; | |
809 fn->line = lineno; | |
810 | |
811 fn->next = functions; | |
812 functions = fn; | |
813 current_tag = tag; | |
814 | |
815 if (lineno >= src->num_lines) | |
816 src->num_lines = lineno + 1; | |
817 /* Now insert it into the source file's list of | |
818 functions. Normally functions will be encountered in | |
819 ascending order, so a simple scan is quick. */ | |
820 for (probe = src->functions, prev = NULL; | |
821 probe && probe->line > lineno; | |
822 prev = probe, probe = probe->line_next) | |
823 continue; | |
824 fn->line_next = probe; | |
825 if (prev) | |
826 prev->line_next = fn; | |
827 else | |
828 src->functions = fn; | |
829 } | |
830 else if (fn && tag == GCOV_TAG_BLOCKS) | |
831 { | |
832 if (fn->blocks) | |
833 fnotice (stderr, "%s:already seen blocks for '%s'\n", | |
834 bbg_file_name, fn->name); | |
835 else | |
836 { | |
837 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length); | |
838 fn->num_blocks = num_blocks; | |
839 | |
840 fn->blocks = XCNEWVEC (block_t, fn->num_blocks); | |
841 for (ix = 0; ix != num_blocks; ix++) | |
842 fn->blocks[ix].flags = gcov_read_unsigned (); | |
843 } | |
844 } | |
845 else if (fn && tag == GCOV_TAG_ARCS) | |
846 { | |
847 unsigned src = gcov_read_unsigned (); | |
848 unsigned num_dests = GCOV_TAG_ARCS_NUM (length); | |
849 | |
850 if (src >= fn->num_blocks || fn->blocks[src].succ) | |
851 goto corrupt; | |
852 | |
853 while (num_dests--) | |
854 { | |
855 struct arc_info *arc; | |
856 unsigned dest = gcov_read_unsigned (); | |
857 unsigned flags = gcov_read_unsigned (); | |
858 | |
859 if (dest >= fn->num_blocks) | |
860 goto corrupt; | |
861 arc = XCNEW (arc_t); | |
862 | |
863 arc->dst = &fn->blocks[dest]; | |
864 arc->src = &fn->blocks[src]; | |
865 | |
866 arc->count = 0; | |
867 arc->count_valid = 0; | |
868 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); | |
869 arc->fake = !!(flags & GCOV_ARC_FAKE); | |
870 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); | |
871 | |
872 arc->succ_next = fn->blocks[src].succ; | |
873 fn->blocks[src].succ = arc; | |
874 fn->blocks[src].num_succ++; | |
875 | |
876 arc->pred_next = fn->blocks[dest].pred; | |
877 fn->blocks[dest].pred = arc; | |
878 fn->blocks[dest].num_pred++; | |
879 | |
880 if (arc->fake) | |
881 { | |
882 if (src) | |
883 { | |
884 /* Exceptional exit from this function, the | |
885 source block must be a call. */ | |
886 fn->blocks[src].is_call_site = 1; | |
887 arc->is_call_non_return = 1; | |
888 } | |
889 else | |
890 { | |
891 /* Non-local return from a callee of this | |
892 function. The destination block is a catch or | |
893 setjmp. */ | |
894 arc->is_nonlocal_return = 1; | |
895 fn->blocks[dest].is_nonlocal_return = 1; | |
896 } | |
897 } | |
898 | |
899 if (!arc->on_tree) | |
900 fn->num_counts++; | |
901 } | |
902 } | |
903 else if (fn && tag == GCOV_TAG_LINES) | |
904 { | |
905 unsigned blockno = gcov_read_unsigned (); | |
906 unsigned *line_nos = XCNEWVEC (unsigned, length - 1); | |
907 | |
908 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding) | |
909 goto corrupt; | |
910 | |
911 for (ix = 0; ; ) | |
912 { | |
913 unsigned lineno = gcov_read_unsigned (); | |
914 | |
915 if (lineno) | |
916 { | |
917 if (!ix) | |
918 { | |
919 line_nos[ix++] = 0; | |
920 line_nos[ix++] = src->index; | |
921 } | |
922 line_nos[ix++] = lineno; | |
923 if (lineno >= src->num_lines) | |
924 src->num_lines = lineno + 1; | |
925 } | |
926 else | |
927 { | |
928 const char *file_name = gcov_read_string (); | |
929 | |
930 if (!file_name) | |
931 break; | |
932 src = find_source (file_name); | |
933 | |
934 line_nos[ix++] = 0; | |
935 line_nos[ix++] = src->index; | |
936 } | |
937 } | |
938 | |
939 fn->blocks[blockno].u.line.encoding = line_nos; | |
940 fn->blocks[blockno].u.line.num = ix; | |
941 } | |
942 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) | |
943 { | |
944 fn = NULL; | |
945 current_tag = 0; | |
946 } | |
947 gcov_sync (base, length); | |
948 if (gcov_is_error ()) | |
949 { | |
950 corrupt:; | |
951 fnotice (stderr, "%s:corrupted\n", bbg_file_name); | |
952 gcov_close (); | |
953 return 1; | |
954 } | |
955 } | |
956 gcov_close (); | |
957 | |
958 /* We built everything backwards, so nreverse them all. */ | |
959 | |
960 /* Reverse sources. Not strictly necessary, but we'll then process | |
961 them in the 'expected' order. */ | |
962 { | |
963 source_t *src, *src_p, *src_n; | |
964 | |
965 for (src_p = NULL, src = sources; src; src_p = src, src = src_n) | |
966 { | |
967 src_n = src->next; | |
968 src->next = src_p; | |
969 } | |
970 sources = src_p; | |
971 } | |
972 | |
973 /* Reverse functions. */ | |
974 { | |
975 function_t *fn, *fn_p, *fn_n; | |
976 | |
977 for (fn_p = old_functions_head, fn = functions; | |
978 fn != old_functions_head; | |
979 fn_p = fn, fn = fn_n) | |
980 { | |
981 unsigned ix; | |
982 | |
983 fn_n = fn->next; | |
984 fn->next = fn_p; | |
985 | |
986 /* Reverse the arcs. */ | |
987 for (ix = fn->num_blocks; ix--;) | |
988 { | |
989 arc_t *arc, *arc_p, *arc_n; | |
990 | |
991 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; | |
992 arc_p = arc, arc = arc_n) | |
993 { | |
994 arc_n = arc->succ_next; | |
995 arc->succ_next = arc_p; | |
996 } | |
997 fn->blocks[ix].succ = arc_p; | |
998 | |
999 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc; | |
1000 arc_p = arc, arc = arc_n) | |
1001 { | |
1002 arc_n = arc->pred_next; | |
1003 arc->pred_next = arc_p; | |
1004 } | |
1005 fn->blocks[ix].pred = arc_p; | |
1006 } | |
1007 } | |
1008 functions = fn_p; | |
1009 } | |
1010 return 0; | |
1011 } | |
1012 | |
1013 /* Reads profiles from the count file and attach to each | |
1014 function. Return nonzero if fatal error. */ | |
1015 | |
1016 static int | |
1017 read_count_file (void) | |
1018 { | |
1019 unsigned ix; | |
1020 unsigned version; | |
1021 unsigned tag; | |
1022 function_t *fn = NULL; | |
1023 int error = 0; | |
1024 | |
1025 if (!gcov_open (da_file_name, 1)) | |
1026 { | |
1027 fnotice (stderr, "%s:cannot open data file, assuming not executed\n", | |
1028 da_file_name); | |
1029 no_data_file = 1; | |
1030 return 0; | |
1031 } | |
1032 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) | |
1033 { | |
1034 fnotice (stderr, "%s:not a gcov data file\n", da_file_name); | |
1035 cleanup:; | |
1036 gcov_close (); | |
1037 return 1; | |
1038 } | |
1039 version = gcov_read_unsigned (); | |
1040 if (version != GCOV_VERSION) | |
1041 { | |
1042 char v[4], e[4]; | |
1043 | |
1044 GCOV_UNSIGNED2STRING (v, version); | |
1045 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); | |
1046 | |
1047 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n", | |
1048 da_file_name, v, e); | |
1049 } | |
1050 tag = gcov_read_unsigned (); | |
1051 if (tag != bbg_stamp) | |
1052 { | |
1053 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name); | |
1054 goto cleanup; | |
1055 } | |
1056 | |
1057 while ((tag = gcov_read_unsigned ())) | |
1058 { | |
1059 unsigned length = gcov_read_unsigned (); | |
1060 unsigned long base = gcov_position (); | |
1061 | |
1062 if (tag == GCOV_TAG_OBJECT_SUMMARY) | |
1063 gcov_read_summary (&object_summary); | |
1064 else if (tag == GCOV_TAG_PROGRAM_SUMMARY) | |
1065 program_count++; | |
1066 else if (tag == GCOV_TAG_FUNCTION) | |
1067 { | |
1068 unsigned ident = gcov_read_unsigned (); | |
1069 struct function_info *fn_n = functions; | |
1070 | |
1071 /* Try to find the function in the list. | |
1072 To speed up the search, first start from the last function | |
1073 found. */ | |
1074 for (fn = fn ? fn->next : NULL; ; fn = fn->next) | |
1075 { | |
1076 if (fn) | |
1077 ; | |
1078 else if ((fn = fn_n)) | |
1079 fn_n = NULL; | |
1080 else | |
1081 { | |
1082 fnotice (stderr, "%s:unknown function '%u'\n", | |
1083 da_file_name, ident); | |
1084 break; | |
1085 } | |
1086 if (fn->ident == ident) | |
1087 break; | |
1088 } | |
1089 | |
1090 if (!fn) | |
1091 ; | |
1092 else if (gcov_read_unsigned () != fn->checksum) | |
1093 { | |
1094 mismatch:; | |
1095 fnotice (stderr, "%s:profile mismatch for '%s'\n", | |
1096 da_file_name, fn->name); | |
1097 goto cleanup; | |
1098 } | |
1099 } | |
1100 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) | |
1101 { | |
1102 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) | |
1103 goto mismatch; | |
1104 | |
1105 if (!fn->counts) | |
1106 fn->counts = XCNEWVEC (gcov_type, fn->num_counts); | |
1107 | |
1108 for (ix = 0; ix != fn->num_counts; ix++) | |
1109 fn->counts[ix] += gcov_read_counter (); | |
1110 } | |
1111 gcov_sync (base, length); | |
1112 if ((error = gcov_is_error ())) | |
1113 { | |
1114 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", | |
1115 da_file_name); | |
1116 goto cleanup; | |
1117 } | |
1118 } | |
1119 | |
1120 gcov_close (); | |
1121 return 0; | |
1122 } | |
1123 | |
1124 /* Solve the flow graph. Propagate counts from the instrumented arcs | |
1125 to the blocks and the uninstrumented arcs. */ | |
1126 | |
1127 static void | |
1128 solve_flow_graph (function_t *fn) | |
1129 { | |
1130 unsigned ix; | |
1131 arc_t *arc; | |
1132 gcov_type *count_ptr = fn->counts; | |
1133 block_t *blk; | |
1134 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ | |
1135 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ | |
1136 | |
1137 if (fn->num_blocks < 2) | |
1138 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n", | |
1139 bbg_file_name, fn->name); | |
1140 else | |
1141 { | |
1142 if (fn->blocks[0].num_pred) | |
1143 fnotice (stderr, "%s:'%s' has arcs to entry block\n", | |
1144 bbg_file_name, fn->name); | |
1145 else | |
1146 /* We can't deduce the entry block counts from the lack of | |
1147 predecessors. */ | |
1148 fn->blocks[0].num_pred = ~(unsigned)0; | |
1149 | |
1150 if (fn->blocks[fn->num_blocks - 1].num_succ) | |
1151 fnotice (stderr, "%s:'%s' has arcs from exit block\n", | |
1152 bbg_file_name, fn->name); | |
1153 else | |
1154 /* Likewise, we can't deduce exit block counts from the lack | |
1155 of its successors. */ | |
1156 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0; | |
1157 } | |
1158 | |
1159 /* Propagate the measured counts, this must be done in the same | |
1160 order as the code in profile.c */ | |
1161 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++) | |
1162 { | |
1163 block_t const *prev_dst = NULL; | |
1164 int out_of_order = 0; | |
1165 int non_fake_succ = 0; | |
1166 | |
1167 for (arc = blk->succ; arc; arc = arc->succ_next) | |
1168 { | |
1169 if (!arc->fake) | |
1170 non_fake_succ++; | |
1171 | |
1172 if (!arc->on_tree) | |
1173 { | |
1174 if (count_ptr) | |
1175 arc->count = *count_ptr++; | |
1176 arc->count_valid = 1; | |
1177 blk->num_succ--; | |
1178 arc->dst->num_pred--; | |
1179 } | |
1180 if (prev_dst && prev_dst > arc->dst) | |
1181 out_of_order = 1; | |
1182 prev_dst = arc->dst; | |
1183 } | |
1184 if (non_fake_succ == 1) | |
1185 { | |
1186 /* If there is only one non-fake exit, it is an | |
1187 unconditional branch. */ | |
1188 for (arc = blk->succ; arc; arc = arc->succ_next) | |
1189 if (!arc->fake) | |
1190 { | |
1191 arc->is_unconditional = 1; | |
1192 /* If this block is instrumenting a call, it might be | |
1193 an artificial block. It is not artificial if it has | |
1194 a non-fallthrough exit, or the destination of this | |
1195 arc has more than one entry. Mark the destination | |
1196 block as a return site, if none of those conditions | |
1197 hold. */ | |
1198 if (blk->is_call_site && arc->fall_through | |
1199 && arc->dst->pred == arc && !arc->pred_next) | |
1200 arc->dst->is_call_return = 1; | |
1201 } | |
1202 } | |
1203 | |
1204 /* Sort the successor arcs into ascending dst order. profile.c | |
1205 normally produces arcs in the right order, but sometimes with | |
1206 one or two out of order. We're not using a particularly | |
1207 smart sort. */ | |
1208 if (out_of_order) | |
1209 { | |
1210 arc_t *start = blk->succ; | |
1211 unsigned changes = 1; | |
1212 | |
1213 while (changes) | |
1214 { | |
1215 arc_t *arc, *arc_p, *arc_n; | |
1216 | |
1217 changes = 0; | |
1218 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) | |
1219 { | |
1220 if (arc->dst > arc_n->dst) | |
1221 { | |
1222 changes = 1; | |
1223 if (arc_p) | |
1224 arc_p->succ_next = arc_n; | |
1225 else | |
1226 start = arc_n; | |
1227 arc->succ_next = arc_n->succ_next; | |
1228 arc_n->succ_next = arc; | |
1229 arc_p = arc_n; | |
1230 } | |
1231 else | |
1232 { | |
1233 arc_p = arc; | |
1234 arc = arc_n; | |
1235 } | |
1236 } | |
1237 } | |
1238 blk->succ = start; | |
1239 } | |
1240 | |
1241 /* Place it on the invalid chain, it will be ignored if that's | |
1242 wrong. */ | |
1243 blk->invalid_chain = 1; | |
1244 blk->chain = invalid_blocks; | |
1245 invalid_blocks = blk; | |
1246 } | |
1247 | |
1248 while (invalid_blocks || valid_blocks) | |
1249 { | |
1250 while ((blk = invalid_blocks)) | |
1251 { | |
1252 gcov_type total = 0; | |
1253 const arc_t *arc; | |
1254 | |
1255 invalid_blocks = blk->chain; | |
1256 blk->invalid_chain = 0; | |
1257 if (!blk->num_succ) | |
1258 for (arc = blk->succ; arc; arc = arc->succ_next) | |
1259 total += arc->count; | |
1260 else if (!blk->num_pred) | |
1261 for (arc = blk->pred; arc; arc = arc->pred_next) | |
1262 total += arc->count; | |
1263 else | |
1264 continue; | |
1265 | |
1266 blk->count = total; | |
1267 blk->count_valid = 1; | |
1268 blk->chain = valid_blocks; | |
1269 blk->valid_chain = 1; | |
1270 valid_blocks = blk; | |
1271 } | |
1272 while ((blk = valid_blocks)) | |
1273 { | |
1274 gcov_type total; | |
1275 arc_t *arc, *inv_arc; | |
1276 | |
1277 valid_blocks = blk->chain; | |
1278 blk->valid_chain = 0; | |
1279 if (blk->num_succ == 1) | |
1280 { | |
1281 block_t *dst; | |
1282 | |
1283 total = blk->count; | |
1284 inv_arc = NULL; | |
1285 for (arc = blk->succ; arc; arc = arc->succ_next) | |
1286 { | |
1287 total -= arc->count; | |
1288 if (!arc->count_valid) | |
1289 inv_arc = arc; | |
1290 } | |
1291 dst = inv_arc->dst; | |
1292 inv_arc->count_valid = 1; | |
1293 inv_arc->count = total; | |
1294 blk->num_succ--; | |
1295 dst->num_pred--; | |
1296 if (dst->count_valid) | |
1297 { | |
1298 if (dst->num_pred == 1 && !dst->valid_chain) | |
1299 { | |
1300 dst->chain = valid_blocks; | |
1301 dst->valid_chain = 1; | |
1302 valid_blocks = dst; | |
1303 } | |
1304 } | |
1305 else | |
1306 { | |
1307 if (!dst->num_pred && !dst->invalid_chain) | |
1308 { | |
1309 dst->chain = invalid_blocks; | |
1310 dst->invalid_chain = 1; | |
1311 invalid_blocks = dst; | |
1312 } | |
1313 } | |
1314 } | |
1315 if (blk->num_pred == 1) | |
1316 { | |
1317 block_t *src; | |
1318 | |
1319 total = blk->count; | |
1320 inv_arc = NULL; | |
1321 for (arc = blk->pred; arc; arc = arc->pred_next) | |
1322 { | |
1323 total -= arc->count; | |
1324 if (!arc->count_valid) | |
1325 inv_arc = arc; | |
1326 } | |
1327 src = inv_arc->src; | |
1328 inv_arc->count_valid = 1; | |
1329 inv_arc->count = total; | |
1330 blk->num_pred--; | |
1331 src->num_succ--; | |
1332 if (src->count_valid) | |
1333 { | |
1334 if (src->num_succ == 1 && !src->valid_chain) | |
1335 { | |
1336 src->chain = valid_blocks; | |
1337 src->valid_chain = 1; | |
1338 valid_blocks = src; | |
1339 } | |
1340 } | |
1341 else | |
1342 { | |
1343 if (!src->num_succ && !src->invalid_chain) | |
1344 { | |
1345 src->chain = invalid_blocks; | |
1346 src->invalid_chain = 1; | |
1347 invalid_blocks = src; | |
1348 } | |
1349 } | |
1350 } | |
1351 } | |
1352 } | |
1353 | |
1354 /* If the graph has been correctly solved, every block will have a | |
1355 valid count. */ | |
1356 for (ix = 0; ix < fn->num_blocks; ix++) | |
1357 if (!fn->blocks[ix].count_valid) | |
1358 { | |
1359 fnotice (stderr, "%s:graph is unsolvable for '%s'\n", | |
1360 bbg_file_name, fn->name); | |
1361 break; | |
1362 } | |
1363 } | |
1364 | |
1365 | |
1366 | |
1367 /* Increment totals in COVERAGE according to arc ARC. */ | |
1368 | |
1369 static void | |
1370 add_branch_counts (coverage_t *coverage, const arc_t *arc) | |
1371 { | |
1372 if (arc->is_call_non_return) | |
1373 { | |
1374 coverage->calls++; | |
1375 if (arc->src->count) | |
1376 coverage->calls_executed++; | |
1377 } | |
1378 else if (!arc->is_unconditional) | |
1379 { | |
1380 coverage->branches++; | |
1381 if (arc->src->count) | |
1382 coverage->branches_executed++; | |
1383 if (arc->count) | |
1384 coverage->branches_taken++; | |
1385 } | |
1386 } | |
1387 | |
1388 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute | |
1389 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. | |
1390 If DP is zero, no decimal point is printed. Only print 100% when | |
1391 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply | |
1392 format TOP. Return pointer to a static string. */ | |
1393 | |
1394 static char const * | |
1395 format_gcov (gcov_type top, gcov_type bottom, int dp) | |
1396 { | |
1397 static char buffer[20]; | |
1398 | |
1399 if (dp >= 0) | |
1400 { | |
1401 float ratio = bottom ? (float)top / bottom : 0; | |
1402 int ix; | |
1403 unsigned limit = 100; | |
1404 unsigned percent; | |
1405 | |
1406 for (ix = dp; ix--; ) | |
1407 limit *= 10; | |
1408 | |
1409 percent = (unsigned) (ratio * limit + (float)0.5); | |
1410 if (percent <= 0 && top) | |
1411 percent = 1; | |
1412 else if (percent >= limit && top != bottom) | |
1413 percent = limit - 1; | |
1414 ix = sprintf (buffer, "%.*u%%", dp + 1, percent); | |
1415 if (dp) | |
1416 { | |
1417 dp++; | |
1418 do | |
1419 { | |
1420 buffer[ix+1] = buffer[ix]; | |
1421 ix--; | |
1422 } | |
1423 while (dp--); | |
1424 buffer[ix + 1] = '.'; | |
1425 } | |
1426 } | |
1427 else | |
1428 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top); | |
1429 | |
1430 return buffer; | |
1431 } | |
1432 | |
1433 | |
1434 /* Output summary info for a function. */ | |
1435 | |
1436 static void | |
1437 function_summary (const coverage_t *coverage, const char *title) | |
1438 { | |
1439 fnotice (stdout, "%s '%s'\n", title, coverage->name); | |
1440 | |
1441 if (coverage->lines) | |
1442 fnotice (stdout, "Lines executed:%s of %d\n", | |
1443 format_gcov (coverage->lines_executed, coverage->lines, 2), | |
1444 coverage->lines); | |
1445 else | |
1446 fnotice (stdout, "No executable lines\n"); | |
1447 | |
1448 if (flag_branches) | |
1449 { | |
1450 if (coverage->branches) | |
1451 { | |
1452 fnotice (stdout, "Branches executed:%s of %d\n", | |
1453 format_gcov (coverage->branches_executed, | |
1454 coverage->branches, 2), | |
1455 coverage->branches); | |
1456 fnotice (stdout, "Taken at least once:%s of %d\n", | |
1457 format_gcov (coverage->branches_taken, | |
1458 coverage->branches, 2), | |
1459 coverage->branches); | |
1460 } | |
1461 else | |
1462 fnotice (stdout, "No branches\n"); | |
1463 if (coverage->calls) | |
1464 fnotice (stdout, "Calls executed:%s of %d\n", | |
1465 format_gcov (coverage->calls_executed, coverage->calls, 2), | |
1466 coverage->calls); | |
1467 else | |
1468 fnotice (stdout, "No calls\n"); | |
1469 } | |
1470 } | |
1471 | |
1472 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS | |
1473 affect name generation. With preserve_paths we create a filename | |
1474 from all path components of the source file, replacing '/' with | |
1475 '#', without it we simply take the basename component. With | |
1476 long_output_names we prepend the processed name of the input file | |
1477 to each output name (except when the current source file is the | |
1478 input file, so you don't get a double concatenation). The two | |
1479 components are separated by '##'. Also '.' filename components are | |
1480 removed and '..' components are renamed to '^'. */ | |
1481 | |
1482 static char * | |
1483 make_gcov_file_name (const char *input_name, const char *src_name) | |
1484 { | |
1485 const char *cptr; | |
1486 char *name; | |
1487 | |
1488 if (flag_long_names && input_name && strcmp (src_name, input_name)) | |
1489 { | |
1490 name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10); | |
1491 name[0] = 0; | |
1492 /* Generate the input filename part. */ | |
1493 cptr = flag_preserve_paths ? NULL : lbasename (input_name); | |
1494 strcat (name, cptr ? cptr : input_name); | |
1495 strcat (name, "##"); | |
1496 } | |
1497 else | |
1498 { | |
1499 name = XNEWVEC (char, strlen (src_name) + 10); | |
1500 name[0] = 0; | |
1501 } | |
1502 | |
1503 /* Generate the source filename part. */ | |
1504 | |
1505 cptr = flag_preserve_paths ? NULL : lbasename (src_name); | |
1506 strcat (name, cptr ? cptr : src_name); | |
1507 | |
1508 if (flag_preserve_paths) | |
1509 { | |
1510 /* Convert '/' and '\' to '#', remove '/./', convert '/../' to '/^/', | |
1511 convert ':' to '~' on DOS based file system. */ | |
1512 char *pnew = name, *pold = name; | |
1513 | |
1514 /* First check for leading drive separator. */ | |
1515 | |
1516 while (*pold != '\0') | |
1517 { | |
1518 if (*pold == '/' || *pold == '\\') | |
1519 { | |
1520 *pnew++ = '#'; | |
1521 pold++; | |
1522 } | |
1523 #if defined (HAVE_DOS_BASED_FILE_SYSTEM) | |
1524 else if (*pold == ':') | |
1525 { | |
1526 *pnew++ = '~'; | |
1527 pold++; | |
1528 } | |
1529 #endif | |
1530 else if ((*pold == '/' && strstr (pold, "/./") == pold) | |
1531 || (*pold == '\\' && strstr (pold, "\\.\\") == pold)) | |
1532 pold += 3; | |
1533 else if (*pold == '/' && strstr (pold, "/../") == pold) | |
1534 { | |
1535 strcpy (pnew, "/^/"); | |
1536 pnew += 3; | |
1537 pold += 4; | |
1538 } | |
1539 else if (*pold == '\\' && strstr (pold, "\\..\\") == pold) | |
1540 { | |
1541 strcpy (pnew, "\\^\\"); | |
1542 pnew += 3; | |
1543 pold += 4; | |
1544 } | |
1545 else | |
1546 *pnew++ = *pold++; | |
1547 } | |
1548 | |
1549 *pnew = '\0'; | |
1550 } | |
1551 | |
1552 strcat (name, ".gcov"); | |
1553 return name; | |
1554 } | |
1555 | |
1556 /* Scan through the bb_data for each line in the block, increment | |
1557 the line number execution count indicated by the execution count of | |
1558 the appropriate basic block. */ | |
1559 | |
1560 static void | |
1561 add_line_counts (coverage_t *coverage, function_t *fn) | |
1562 { | |
1563 unsigned ix; | |
1564 line_t *line = NULL; /* This is propagated from one iteration to the | |
1565 next. */ | |
1566 | |
1567 /* Scan each basic block. */ | |
1568 for (ix = 0; ix != fn->num_blocks; ix++) | |
1569 { | |
1570 block_t *block = &fn->blocks[ix]; | |
1571 unsigned *encoding; | |
1572 const source_t *src = NULL; | |
1573 unsigned jx; | |
1574 | |
1575 if (block->count && ix && ix + 1 != fn->num_blocks) | |
1576 fn->blocks_executed++; | |
1577 for (jx = 0, encoding = block->u.line.encoding; | |
1578 jx != block->u.line.num; jx++, encoding++) | |
1579 if (!*encoding) | |
1580 { | |
1581 unsigned src_n = *++encoding; | |
1582 | |
1583 for (src = sources; src->index != src_n; src = src->next) | |
1584 continue; | |
1585 jx++; | |
1586 } | |
1587 else | |
1588 { | |
1589 line = &src->lines[*encoding]; | |
1590 | |
1591 if (coverage) | |
1592 { | |
1593 if (!line->exists) | |
1594 coverage->lines++; | |
1595 if (!line->count && block->count) | |
1596 coverage->lines_executed++; | |
1597 } | |
1598 line->exists = 1; | |
1599 line->count += block->count; | |
1600 } | |
1601 free (block->u.line.encoding); | |
1602 block->u.cycle.arc = NULL; | |
1603 block->u.cycle.ident = ~0U; | |
1604 | |
1605 if (!ix || ix + 1 == fn->num_blocks) | |
1606 /* Entry or exit block */; | |
1607 else if (flag_all_blocks) | |
1608 { | |
1609 line_t *block_line = line ? line : &fn->src->lines[fn->line]; | |
1610 | |
1611 block->chain = block_line->u.blocks; | |
1612 block_line->u.blocks = block; | |
1613 } | |
1614 else if (flag_branches) | |
1615 { | |
1616 arc_t *arc; | |
1617 | |
1618 for (arc = block->succ; arc; arc = arc->succ_next) | |
1619 { | |
1620 arc->line_next = line->u.branches; | |
1621 line->u.branches = arc; | |
1622 if (coverage && !arc->is_unconditional) | |
1623 add_branch_counts (coverage, arc); | |
1624 } | |
1625 } | |
1626 } | |
1627 if (!line) | |
1628 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name); | |
1629 } | |
1630 | |
1631 /* Accumulate the line counts of a file. */ | |
1632 | |
1633 static void | |
1634 accumulate_line_counts (source_t *src) | |
1635 { | |
1636 line_t *line; | |
1637 function_t *fn, *fn_p, *fn_n; | |
1638 unsigned ix; | |
1639 | |
1640 /* Reverse the function order. */ | |
1641 for (fn = src->functions, fn_p = NULL; fn; | |
1642 fn_p = fn, fn = fn_n) | |
1643 { | |
1644 fn_n = fn->line_next; | |
1645 fn->line_next = fn_p; | |
1646 } | |
1647 src->functions = fn_p; | |
1648 | |
1649 for (ix = src->num_lines, line = src->lines; ix--; line++) | |
1650 { | |
1651 if (!flag_all_blocks) | |
1652 { | |
1653 arc_t *arc, *arc_p, *arc_n; | |
1654 | |
1655 /* Total and reverse the branch information. */ | |
1656 for (arc = line->u.branches, arc_p = NULL; arc; | |
1657 arc_p = arc, arc = arc_n) | |
1658 { | |
1659 arc_n = arc->line_next; | |
1660 arc->line_next = arc_p; | |
1661 | |
1662 add_branch_counts (&src->coverage, arc); | |
1663 } | |
1664 line->u.branches = arc_p; | |
1665 } | |
1666 else if (line->u.blocks) | |
1667 { | |
1668 /* The user expects the line count to be the number of times | |
1669 a line has been executed. Simply summing the block count | |
1670 will give an artificially high number. The Right Thing | |
1671 is to sum the entry counts to the graph of blocks on this | |
1672 line, then find the elementary cycles of the local graph | |
1673 and add the transition counts of those cycles. */ | |
1674 block_t *block, *block_p, *block_n; | |
1675 gcov_type count = 0; | |
1676 | |
1677 /* Reverse the block information. */ | |
1678 for (block = line->u.blocks, block_p = NULL; block; | |
1679 block_p = block, block = block_n) | |
1680 { | |
1681 block_n = block->chain; | |
1682 block->chain = block_p; | |
1683 block->u.cycle.ident = ix; | |
1684 } | |
1685 line->u.blocks = block_p; | |
1686 | |
1687 /* Sum the entry arcs. */ | |
1688 for (block = line->u.blocks; block; block = block->chain) | |
1689 { | |
1690 arc_t *arc; | |
1691 | |
1692 for (arc = block->pred; arc; arc = arc->pred_next) | |
1693 { | |
1694 if (arc->src->u.cycle.ident != ix) | |
1695 count += arc->count; | |
1696 if (flag_branches) | |
1697 add_branch_counts (&src->coverage, arc); | |
1698 } | |
1699 | |
1700 /* Initialize the cs_count. */ | |
1701 for (arc = block->succ; arc; arc = arc->succ_next) | |
1702 arc->cs_count = arc->count; | |
1703 } | |
1704 | |
1705 /* Find the loops. This uses the algorithm described in | |
1706 Tiernan 'An Efficient Search Algorithm to Find the | |
1707 Elementary Circuits of a Graph', CACM Dec 1970. We hold | |
1708 the P array by having each block point to the arc that | |
1709 connects to the previous block. The H array is implicitly | |
1710 held because of the arc ordering, and the block's | |
1711 previous arc pointer. | |
1712 | |
1713 Although the algorithm is O(N^3) for highly connected | |
1714 graphs, at worst we'll have O(N^2), as most blocks have | |
1715 only one or two exits. Most graphs will be small. | |
1716 | |
1717 For each loop we find, locate the arc with the smallest | |
1718 transition count, and add that to the cumulative | |
1719 count. Decrease flow over the cycle and remove the arc | |
1720 from consideration. */ | |
1721 for (block = line->u.blocks; block; block = block->chain) | |
1722 { | |
1723 block_t *head = block; | |
1724 arc_t *arc; | |
1725 | |
1726 next_vertex:; | |
1727 arc = head->succ; | |
1728 current_vertex:; | |
1729 while (arc) | |
1730 { | |
1731 block_t *dst = arc->dst; | |
1732 if (/* Already used that arc. */ | |
1733 arc->cycle | |
1734 /* Not to same graph, or before first vertex. */ | |
1735 || dst->u.cycle.ident != ix | |
1736 /* Already in path. */ | |
1737 || dst->u.cycle.arc) | |
1738 { | |
1739 arc = arc->succ_next; | |
1740 continue; | |
1741 } | |
1742 | |
1743 if (dst == block) | |
1744 { | |
1745 /* Found a closing arc. */ | |
1746 gcov_type cycle_count = arc->cs_count; | |
1747 arc_t *cycle_arc = arc; | |
1748 arc_t *probe_arc; | |
1749 | |
1750 /* Locate the smallest arc count of the loop. */ | |
1751 for (dst = head; (probe_arc = dst->u.cycle.arc); | |
1752 dst = probe_arc->src) | |
1753 if (cycle_count > probe_arc->cs_count) | |
1754 { | |
1755 cycle_count = probe_arc->cs_count; | |
1756 cycle_arc = probe_arc; | |
1757 } | |
1758 | |
1759 count += cycle_count; | |
1760 cycle_arc->cycle = 1; | |
1761 | |
1762 /* Remove the flow from the cycle. */ | |
1763 arc->cs_count -= cycle_count; | |
1764 for (dst = head; (probe_arc = dst->u.cycle.arc); | |
1765 dst = probe_arc->src) | |
1766 probe_arc->cs_count -= cycle_count; | |
1767 | |
1768 /* Unwind to the cyclic arc. */ | |
1769 while (head != cycle_arc->src) | |
1770 { | |
1771 arc = head->u.cycle.arc; | |
1772 head->u.cycle.arc = NULL; | |
1773 head = arc->src; | |
1774 } | |
1775 /* Move on. */ | |
1776 arc = arc->succ_next; | |
1777 continue; | |
1778 } | |
1779 | |
1780 /* Add new block to chain. */ | |
1781 dst->u.cycle.arc = arc; | |
1782 head = dst; | |
1783 goto next_vertex; | |
1784 } | |
1785 /* We could not add another vertex to the path. Remove | |
1786 the last vertex from the list. */ | |
1787 arc = head->u.cycle.arc; | |
1788 if (arc) | |
1789 { | |
1790 /* It was not the first vertex. Move onto next arc. */ | |
1791 head->u.cycle.arc = NULL; | |
1792 head = arc->src; | |
1793 arc = arc->succ_next; | |
1794 goto current_vertex; | |
1795 } | |
1796 /* Mark this block as unusable. */ | |
1797 block->u.cycle.ident = ~0U; | |
1798 } | |
1799 | |
1800 line->count = count; | |
1801 } | |
1802 | |
1803 if (line->exists) | |
1804 { | |
1805 src->coverage.lines++; | |
1806 if (line->count) | |
1807 src->coverage.lines_executed++; | |
1808 } | |
1809 } | |
1810 } | |
1811 | |
1812 /* Output information about ARC number IX. Returns nonzero if | |
1813 anything is output. */ | |
1814 | |
1815 static int | |
1816 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) | |
1817 { | |
1818 | |
1819 if (arc->is_call_non_return) | |
1820 { | |
1821 if (arc->src->count) | |
1822 { | |
1823 fnotice (gcov_file, "call %2d returned %s\n", ix, | |
1824 format_gcov (arc->src->count - arc->count, | |
1825 arc->src->count, -flag_counts)); | |
1826 } | |
1827 else | |
1828 fnotice (gcov_file, "call %2d never executed\n", ix); | |
1829 } | |
1830 else if (!arc->is_unconditional) | |
1831 { | |
1832 if (arc->src->count) | |
1833 fnotice (gcov_file, "branch %2d taken %s%s\n", ix, | |
1834 format_gcov (arc->count, arc->src->count, -flag_counts), | |
1835 arc->fall_through ? " (fallthrough)" : ""); | |
1836 else | |
1837 fnotice (gcov_file, "branch %2d never executed\n", ix); | |
1838 } | |
1839 else if (flag_unconditional && !arc->dst->is_call_return) | |
1840 { | |
1841 if (arc->src->count) | |
1842 fnotice (gcov_file, "unconditional %2d taken %s\n", ix, | |
1843 format_gcov (arc->count, arc->src->count, -flag_counts)); | |
1844 else | |
1845 fnotice (gcov_file, "unconditional %2d never executed\n", ix); | |
1846 } | |
1847 else | |
1848 return 0; | |
1849 return 1; | |
1850 | |
1851 } | |
1852 | |
1853 /* Read in the source file one line at a time, and output that line to | |
1854 the gcov file preceded by its execution count and other | |
1855 information. */ | |
1856 | |
1857 static void | |
1858 output_lines (FILE *gcov_file, const source_t *src) | |
1859 { | |
1860 FILE *source_file; | |
1861 unsigned line_num; /* current line number. */ | |
1862 const line_t *line; /* current line info ptr. */ | |
1863 char string[STRING_SIZE]; /* line buffer. */ | |
1864 char const *retval = ""; /* status of source file reading. */ | |
1865 function_t *fn = NULL; | |
1866 | |
1867 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name); | |
1868 if (!multiple_files) | |
1869 { | |
1870 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name); | |
1871 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, | |
1872 no_data_file ? "-" : da_file_name); | |
1873 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, | |
1874 object_summary.ctrs[GCOV_COUNTER_ARCS].runs); | |
1875 } | |
1876 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count); | |
1877 | |
1878 source_file = fopen (src->name, "r"); | |
1879 if (!source_file) | |
1880 { | |
1881 fnotice (stderr, "%s:cannot open source file\n", src->name); | |
1882 retval = NULL; | |
1883 } | |
1884 else if (src->file_time == 0) | |
1885 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0); | |
1886 | |
1887 if (flag_branches) | |
1888 fn = src->functions; | |
1889 | |
1890 for (line_num = 1, line = &src->lines[line_num]; | |
1891 line_num < src->num_lines; line_num++, line++) | |
1892 { | |
1893 for (; fn && fn->line == line_num; fn = fn->line_next) | |
1894 { | |
1895 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred; | |
1896 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count; | |
1897 | |
1898 for (; arc; arc = arc->pred_next) | |
1899 if (arc->fake) | |
1900 return_count -= arc->count; | |
1901 | |
1902 fprintf (gcov_file, "function %s", fn->name); | |
1903 fprintf (gcov_file, " called %s", | |
1904 format_gcov (fn->blocks[0].count, 0, -1)); | |
1905 fprintf (gcov_file, " returned %s", | |
1906 format_gcov (return_count, fn->blocks[0].count, 0)); | |
1907 fprintf (gcov_file, " blocks executed %s", | |
1908 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0)); | |
1909 fprintf (gcov_file, "\n"); | |
1910 } | |
1911 | |
1912 /* For lines which don't exist in the .bb file, print '-' before | |
1913 the source line. For lines which exist but were never | |
1914 executed, print '#####' before the source line. Otherwise, | |
1915 print the execution count before the source line. There are | |
1916 16 spaces of indentation added before the source line so that | |
1917 tabs won't be messed up. */ | |
1918 fprintf (gcov_file, "%9s:%5u:", | |
1919 !line->exists ? "-" : !line->count ? "#####" | |
1920 : format_gcov (line->count, 0, -1), line_num); | |
1921 | |
1922 if (retval) | |
1923 { | |
1924 /* Copy source line. */ | |
1925 do | |
1926 { | |
1927 retval = fgets (string, STRING_SIZE, source_file); | |
1928 if (!retval) | |
1929 break; | |
1930 fputs (retval, gcov_file); | |
1931 } | |
1932 while (!retval[0] || retval[strlen (retval) - 1] != '\n'); | |
1933 } | |
1934 if (!retval) | |
1935 fputs ("/*EOF*/\n", gcov_file); | |
1936 | |
1937 if (flag_all_blocks) | |
1938 { | |
1939 block_t *block; | |
1940 arc_t *arc; | |
1941 int ix, jx; | |
1942 | |
1943 for (ix = jx = 0, block = line->u.blocks; block; | |
1944 block = block->chain) | |
1945 { | |
1946 if (!block->is_call_return) | |
1947 fprintf (gcov_file, "%9s:%5u-block %2d\n", | |
1948 !line->exists ? "-" : !block->count ? "$$$$$" | |
1949 : format_gcov (block->count, 0, -1), | |
1950 line_num, ix++); | |
1951 if (flag_branches) | |
1952 for (arc = block->succ; arc; arc = arc->succ_next) | |
1953 jx += output_branch_count (gcov_file, jx, arc); | |
1954 } | |
1955 } | |
1956 else if (flag_branches) | |
1957 { | |
1958 int ix; | |
1959 arc_t *arc; | |
1960 | |
1961 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next) | |
1962 ix += output_branch_count (gcov_file, ix, arc); | |
1963 } | |
1964 } | |
1965 | |
1966 /* Handle all remaining source lines. There may be lines after the | |
1967 last line of code. */ | |
1968 if (retval) | |
1969 { | |
1970 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++) | |
1971 { | |
1972 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval); | |
1973 | |
1974 while (!retval[0] || retval[strlen (retval) - 1] != '\n') | |
1975 { | |
1976 retval = fgets (string, STRING_SIZE, source_file); | |
1977 if (!retval) | |
1978 break; | |
1979 fputs (retval, gcov_file); | |
1980 } | |
1981 } | |
1982 } | |
1983 | |
1984 if (source_file) | |
1985 fclose (source_file); | |
1986 } |