00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "config.h"
00047 #include "system.h"
00048 #include "intl.h"
00049 #include "version.h"
00050 #undef abort
00051
00052 #include <getopt.h>
00053
00054 typedef HOST_WIDEST_INT gcov_type;
00055 #include "gcov-io.h"
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 #define STRING_SIZE 200
00088
00089
00090
00091
00092 struct sourcefile
00093 {
00094 char *name;
00095 int maxlineno;
00096 struct sourcefile *next;
00097 };
00098
00099
00100
00101 struct sourcefile *sources;
00102
00103
00104
00105
00106 struct adj_list
00107 {
00108 int source;
00109 int target;
00110 gcov_type arc_count;
00111 unsigned int count_valid : 1;
00112 unsigned int on_tree : 1;
00113 unsigned int fake : 1;
00114 unsigned int fall_through : 1;
00115 #if 0
00116
00117 rtx branch_insn;
00118 #endif
00119 struct adj_list *pred_next;
00120 struct adj_list *succ_next;
00121 };
00122
00123
00124
00125
00126 struct bb_info
00127 {
00128 struct adj_list *succ;
00129 struct adj_list *pred;
00130 gcov_type succ_count;
00131 gcov_type pred_count;
00132 gcov_type exec_count;
00133 unsigned int count_valid : 1;
00134 unsigned int on_tree : 1;
00135 #if 0
00136
00137 rtx first_insn;
00138 #endif
00139 };
00140
00141
00142
00143
00144 struct arcdata
00145 {
00146 gcov_type hits;
00147 gcov_type total;
00148 int call_insn;
00149 struct arcdata *next;
00150 };
00151
00152
00153
00154 struct bb_info_list
00155 {
00156
00157 struct bb_info *bb_graph;
00158 int num_blocks;
00159 struct bb_info_list *next;
00160 };
00161
00162
00163 struct line_info
00164 {
00165 gcov_type count;
00166 struct arcdata *branches;
00167 unsigned exists : 1;
00168 };
00169
00170 struct coverage
00171 {
00172 int lines;
00173 int lines_executed;
00174
00175 int branches;
00176 int branches_executed;
00177 int branches_taken;
00178
00179 int calls;
00180 int calls_executed;
00181
00182 char *name;
00183 };
00184
00185
00186
00187 static struct bb_info_list *bb_graph_list = 0;
00188
00189
00190
00191 static time_t bb_file_time;
00192
00193
00194
00195 static char *bbg_file_name;
00196 static FILE *bbg_file;
00197
00198
00199
00200 static char *da_file_name;
00201 static FILE *da_file;
00202
00203
00204
00205 static char *bb_file_name;
00206 static FILE *bb_file;
00207
00208
00209
00210 static char *bb_data;
00211
00212
00213
00214 static long bb_data_size;
00215
00216
00217
00218 static char *input_file_name = 0;
00219
00220
00221
00222 static int output_branch_probs = 0;
00223
00224
00225
00226
00227 static int output_gcov_file = 1;
00228
00229
00230
00231
00232
00233
00234 static int output_long_names = 0;
00235
00236
00237
00238 static int output_function_summary = 0;
00239
00240
00241
00242
00243 static char *object_directory = 0;
00244
00245
00246
00247 static int preserve_paths = 0;
00248
00249
00250
00251
00252 static int output_branch_counts = 0;
00253
00254
00255 static void process_args PARAMS ((int, char **));
00256 static void open_files PARAMS ((void));
00257 static void read_files PARAMS ((void));
00258 static void scan_for_source_files PARAMS ((void));
00259 static void output_data PARAMS ((struct sourcefile *));
00260 static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
00261 static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
00262 static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
00263 static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
00264 static gcov_type *read_profile PARAMS ((char *, long, int));
00265 static void create_program_flow_graph PARAMS ((struct bb_info_list *));
00266 static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
00267 static void accumulate_branch_counts PARAMS ((struct coverage *,
00268 struct arcdata *));
00269 static void calculate_branch_probs PARAMS ((struct bb_info *,
00270 struct line_info *,
00271 struct coverage *));
00272 static void function_summary PARAMS ((struct coverage *, const char *));
00273 static void init_line_info PARAMS ((struct line_info *,
00274 struct coverage *, long));
00275 static void output_line_info PARAMS ((FILE *, const struct line_info *,
00276 const struct coverage *, long));
00277 static char *make_gcov_file_name PARAMS ((char *));
00278 static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
00279 int));
00280
00281 extern int main PARAMS ((int, char **));
00282
00283 int
00284 main (argc, argv)
00285 int argc;
00286 char **argv;
00287 {
00288 struct sourcefile *s_ptr;
00289
00290 gcc_init_libintl ();
00291
00292 process_args (argc, argv);
00293
00294 open_files ();
00295
00296 read_files ();
00297
00298 scan_for_source_files ();
00299
00300 for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
00301 output_data (s_ptr);
00302
00303 return 0;
00304 }
00305
00306 static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
00307 static void
00308 fnotice VPARAMS ((FILE *file, const char *msgid, ...))
00309 {
00310 VA_OPEN (ap, msgid);
00311 VA_FIXEDARG (ap, FILE *, file);
00312 VA_FIXEDARG (ap, const char *, msgid);
00313
00314 vfprintf (file, _(msgid), ap);
00315 VA_CLOSE (ap);
00316 }
00317
00318
00319
00320 extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
00321
00322 void
00323 fancy_abort ()
00324 {
00325 fnotice (stderr, "Internal gcov abort.\n");
00326 exit (FATAL_EXIT_CODE);
00327 }
00328
00329
00330
00331
00332 static void
00333 print_usage (error_p)
00334 int error_p;
00335 {
00336 FILE *file = error_p ? stderr : stdout;
00337 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
00338 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
00339 fnotice (file, "Print code coverage information.\n\n");
00340 fnotice (file, " -h, --help Print this help, then exit\n");
00341 fnotice (file, " -v, --version Print version number, then exit\n");
00342 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
00343 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
00344 rather than percentages\n");
00345 fnotice (file, " -n, --no-output Do not create an output file\n");
00346 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
00347 source files\n");
00348 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
00349 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
00350 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
00351 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
00352 bug_report_url);
00353 exit (status);
00354 }
00355
00356
00357
00358 static void
00359 print_version ()
00360 {
00361 fnotice (stdout, "gcov (GCC) %s\n", version_string);
00362 fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
00363 fnotice (stdout,
00364 "This is free software; see the source for copying conditions. There is NO\n\
00365 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
00366 exit (SUCCESS_EXIT_CODE);
00367 }
00368
00369 static const struct option options[] =
00370 {
00371 { "help", no_argument, NULL, 'h' },
00372 { "version", no_argument, NULL, 'v' },
00373 { "branch-probabilities", no_argument, NULL, 'b' },
00374 { "branch-counts", no_argument, NULL, 'c' },
00375 { "no-output", no_argument, NULL, 'n' },
00376 { "long-file-names", no_argument, NULL, 'l' },
00377 { "function-summaries", no_argument, NULL, 'f' },
00378 { "preserve-paths", no_argument, NULL, 'p' },
00379 { "object-directory", required_argument, NULL, 'o' },
00380 { "object-file", required_argument, NULL, 'o' },
00381 };
00382
00383
00384
00385 static void
00386 process_args (argc, argv)
00387 int argc;
00388 char **argv;
00389 {
00390 int opt;
00391
00392 while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
00393 {
00394 switch (opt)
00395 {
00396 case 'h':
00397 print_usage (false);
00398
00399 case 'v':
00400 print_version ();
00401
00402 case 'b':
00403 output_branch_probs = 1;
00404 break;
00405 case 'c':
00406 output_branch_counts = 1;
00407 break;
00408 case 'n':
00409 output_gcov_file = 0;
00410 break;
00411 case 'l':
00412 output_long_names = 1;
00413 break;
00414 case 'f':
00415 output_function_summary = 1;
00416 break;
00417 case 'o':
00418 object_directory = optarg;
00419 break;
00420 case 'p':
00421 preserve_paths = 1;
00422 break;
00423 default:
00424 print_usage (true);
00425
00426 }
00427 }
00428
00429 if (optind != argc - 1)
00430 print_usage (true);
00431
00432 input_file_name = argv[optind];
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 static void
00445 open_files ()
00446 {
00447 char *cptr;
00448 char *name;
00449 int length = strlen (input_file_name);
00450 int base;
00451
00452 if (object_directory && object_directory[0])
00453 {
00454 struct stat status;
00455
00456 length += strlen (object_directory) + 2;
00457 name = xmalloc (length);
00458 name[0] = 0;
00459
00460 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
00461 strcat (name, object_directory);
00462 if (base && name[strlen (name) - 1] != '/')
00463 strcat (name, "/");
00464 }
00465 else
00466 {
00467 name = xmalloc (length + 1);
00468 name[0] = 0;
00469 base = 1;
00470 }
00471
00472 if (base)
00473 {
00474
00475 cptr = strrchr (input_file_name, '/');
00476 cptr = cptr ? cptr + 1 : input_file_name;
00477
00478 strcat (name, cptr);
00479 }
00480
00481 cptr = strrchr (name, '.');
00482 if (cptr)
00483 *cptr = 0;
00484
00485 length = strlen (name);
00486 da_file_name = xmalloc (length + 4);
00487 bb_file_name = xmalloc (length + 4);
00488 bbg_file_name = xmalloc (length + 5);
00489
00490 strcpy (da_file_name, name);
00491 strcpy (bb_file_name, name);
00492 strcpy (bbg_file_name, name);
00493 strcpy (da_file_name + length, ".da");
00494 strcpy (bb_file_name + length, ".bb");
00495 strcpy (bbg_file_name + length, ".bbg");
00496
00497 bb_file = fopen (bb_file_name, "rb");
00498 if (bb_file == NULL)
00499 {
00500 fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
00501 exit (FATAL_EXIT_CODE);
00502 }
00503
00504 bbg_file = fopen (bbg_file_name, "rb");
00505 if (bbg_file == NULL)
00506 {
00507 fnotice (stderr, "Could not open program flow graph file %s.\n",
00508 bbg_file_name);
00509 exit (FATAL_EXIT_CODE);
00510 }
00511
00512 {
00513 struct stat status;
00514
00515 if (!fstat (fileno (bb_file), &status))
00516 bb_file_time = status.st_mtime;
00517 }
00518
00519
00520
00521 da_file = fopen (da_file_name, "rb");
00522 if (da_file == NULL)
00523 {
00524 fnotice (stderr, "Could not open data file %s.\n", da_file_name);
00525 fnotice (stderr, "Assuming that all execution counts are zero.\n");
00526 }
00527
00528
00529
00530
00531 ungetc (getc (bbg_file), bbg_file);
00532 if (feof (bbg_file))
00533 {
00534 fnotice (stderr, "No executable code associated with file %s.\n",
00535 input_file_name);
00536 exit (FATAL_EXIT_CODE);
00537 }
00538 }
00539
00540
00541
00542 static void
00543 init_arc (arcptr, source, target, bb_graph)
00544 struct adj_list *arcptr;
00545 int source, target;
00546 struct bb_info *bb_graph;
00547 {
00548 arcptr->target = target;
00549 arcptr->source = source;
00550
00551 arcptr->arc_count = 0;
00552 arcptr->count_valid = 0;
00553 arcptr->on_tree = 0;
00554 arcptr->fake = 0;
00555 arcptr->fall_through = 0;
00556
00557 arcptr->succ_next = bb_graph[source].succ;
00558 bb_graph[source].succ = arcptr;
00559 bb_graph[source].succ_count++;
00560
00561 arcptr->pred_next = bb_graph[target].pred;
00562 bb_graph[target].pred = arcptr;
00563 bb_graph[target].pred_count++;
00564 }
00565
00566
00567
00568 static struct adj_list *
00569 reverse_arcs (arcptr)
00570 struct adj_list *arcptr;
00571 {
00572 struct adj_list *prev = 0;
00573 struct adj_list *next;
00574
00575 for ( ; arcptr; arcptr = next)
00576 {
00577 next = arcptr->succ_next;
00578 arcptr->succ_next = prev;
00579 prev = arcptr;
00580 }
00581
00582 return prev;
00583 }
00584
00585
00586
00587 static gcov_type *
00588 read_profile (function_name, cfg_checksum, instr_arcs)
00589 char *function_name;
00590 long cfg_checksum;
00591 int instr_arcs;
00592 {
00593 int i;
00594 int okay = 1;
00595 gcov_type *profile;
00596 char *function_name_buffer;
00597 int function_name_buffer_len;
00598
00599 profile = xmalloc (sizeof (gcov_type) * instr_arcs);
00600 function_name_buffer_len = strlen (function_name) + 1;
00601 function_name_buffer = xmalloc (function_name_buffer_len + 1);
00602
00603 for (i = 0; i < instr_arcs; i++)
00604 profile[i] = 0;
00605
00606 if (!da_file)
00607 return profile;
00608
00609 rewind (da_file);
00610 while (1)
00611 {
00612 long magic, extra_bytes;
00613 long func_count;
00614 int i;
00615
00616 if (__read_long (&magic, da_file, 4) != 0)
00617 break;
00618
00619 if (magic != -123)
00620 {
00621 okay = 0;
00622 break;
00623 }
00624
00625 if (__read_long (&func_count, da_file, 4) != 0)
00626 {
00627 okay = 0;
00628 break;
00629 }
00630
00631 if (__read_long (&extra_bytes, da_file, 4) != 0)
00632 {
00633 okay = 0;
00634 break;
00635 }
00636
00637
00638 fseek (da_file, extra_bytes, SEEK_CUR);
00639
00640 for (i = 0; i < func_count; i++)
00641 {
00642 long arc_count;
00643 long chksum;
00644 int j;
00645
00646 if (__read_gcov_string
00647 (function_name_buffer, function_name_buffer_len, da_file,
00648 -1) != 0)
00649 {
00650 okay = 0;
00651 break;
00652 }
00653
00654 if (__read_long (&chksum, da_file, 4) != 0)
00655 {
00656 okay = 0;
00657 break;
00658 }
00659
00660 if (__read_long (&arc_count, da_file, 4) != 0)
00661 {
00662 okay = 0;
00663 break;
00664 }
00665
00666 if (strcmp (function_name_buffer, function_name) != 0
00667 || arc_count != instr_arcs || chksum != cfg_checksum)
00668 {
00669
00670 if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
00671 {
00672 okay = 0;
00673 break;
00674 }
00675 }
00676 else
00677 {
00678 gcov_type tmp;
00679
00680 for (j = 0; j < arc_count; j++)
00681 if (__read_gcov_type (&tmp, da_file, 8) != 0)
00682 {
00683 okay = 0;
00684 break;
00685 }
00686 else
00687 {
00688 profile[j] += tmp;
00689 }
00690 }
00691 }
00692
00693 if (!okay)
00694 break;
00695
00696 }
00697
00698 free (function_name_buffer);
00699
00700 if (!okay)
00701 {
00702 fprintf (stderr, ".da file corrupted!\n");
00703 free (profile);
00704 abort ();
00705 }
00706
00707 return profile;
00708 }
00709
00710
00711
00712
00713 static void
00714 create_program_flow_graph (bptr)
00715 struct bb_info_list *bptr;
00716 {
00717 long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
00718 int i;
00719 struct adj_list *arcptr;
00720 struct bb_info *bb_graph;
00721 long cfg_checksum;
00722 long instr_arcs = 0;
00723 gcov_type *profile;
00724 int profile_pos = 0;
00725 char *function_name;
00726 long function_name_len, tmp;
00727
00728
00729 __read_long (&tmp, bbg_file, 4);
00730 __read_long (&function_name_len, bbg_file, 4);
00731 function_name = xmalloc (function_name_len + 1);
00732 fread (function_name, 1, function_name_len + 1, bbg_file);
00733
00734
00735 tmp = (function_name_len + 1) % 4;
00736
00737 if (tmp)
00738 fseek (bbg_file, 4 - tmp, SEEK_CUR);
00739
00740 __read_long (&tmp, bbg_file, 4);
00741
00742
00743 __read_long (&cfg_checksum, bbg_file, 4);
00744
00745
00746 __read_long (&num_blocks, bbg_file, 4);
00747
00748
00749 bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
00750
00751 bptr->bb_graph = bb_graph;
00752 bptr->num_blocks = num_blocks;
00753
00754
00755 __read_long (&number_arcs, bbg_file, 4);
00756 for (i = 0; i < num_blocks; i++)
00757 {
00758 int j;
00759
00760 __read_long (&num_arcs_per_block, bbg_file, 4);
00761 for (j = 0; j < num_arcs_per_block; j++)
00762 {
00763 if (number_arcs-- < 0)
00764 abort ();
00765
00766 src = i;
00767 __read_long (&dest, bbg_file, 4);
00768
00769 arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
00770 init_arc (arcptr, src, dest, bb_graph);
00771
00772 __read_long (&flag_bits, bbg_file, 4);
00773 if (flag_bits & 0x1)
00774 arcptr->on_tree++;
00775 else
00776 instr_arcs++;
00777 arcptr->fake = !! (flag_bits & 0x2);
00778 arcptr->fall_through = !! (flag_bits & 0x4);
00779 }
00780 }
00781
00782 if (number_arcs)
00783 abort ();
00784
00785
00786
00787 __read_long (&src, bbg_file, 4);
00788 if (src != -1)
00789 abort ();
00790
00791
00792
00793
00794 for (i = 0; i < num_blocks; i++)
00795 if (bb_graph[i].succ)
00796 bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
00797
00798
00799
00800 profile = read_profile (function_name, cfg_checksum, instr_arcs);
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810 for (i = 0; i < num_blocks; i++)
00811 for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
00812 if (! arcptr->on_tree)
00813 {
00814 arcptr->arc_count = profile[profile_pos++];
00815 arcptr->count_valid = 1;
00816 bb_graph[i].succ_count--;
00817 bb_graph[arcptr->target].pred_count--;
00818 }
00819 free (profile);
00820 free (function_name);
00821 }
00822
00823 static void
00824 solve_program_flow_graph (bptr)
00825 struct bb_info_list *bptr;
00826 {
00827 int passes, changes;
00828 gcov_type total;
00829 int i;
00830 struct adj_list *arcptr;
00831 struct bb_info *bb_graph;
00832 int num_blocks;
00833
00834 num_blocks = bptr->num_blocks;
00835 bb_graph = bptr->bb_graph;
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854 changes = 1;
00855 passes = 0;
00856 while (changes)
00857 {
00858 passes++;
00859 changes = 0;
00860
00861 for (i = num_blocks - 1; i >= 0; i--)
00862 {
00863 if (! bb_graph[i].count_valid)
00864 {
00865 if (bb_graph[i].succ_count == 0)
00866 {
00867 total = 0;
00868 for (arcptr = bb_graph[i].succ; arcptr;
00869 arcptr = arcptr->succ_next)
00870 total += arcptr->arc_count;
00871 bb_graph[i].exec_count = total;
00872 bb_graph[i].count_valid = 1;
00873 changes = 1;
00874 }
00875 else if (bb_graph[i].pred_count == 0)
00876 {
00877 total = 0;
00878 for (arcptr = bb_graph[i].pred; arcptr;
00879 arcptr = arcptr->pred_next)
00880 total += arcptr->arc_count;
00881 bb_graph[i].exec_count = total;
00882 bb_graph[i].count_valid = 1;
00883 changes = 1;
00884 }
00885 }
00886 if (bb_graph[i].count_valid)
00887 {
00888 if (bb_graph[i].succ_count == 1)
00889 {
00890 total = 0;
00891
00892
00893 for (arcptr = bb_graph[i].succ; arcptr;
00894 arcptr = arcptr->succ_next)
00895 total += arcptr->arc_count;
00896
00897 total = bb_graph[i].exec_count - total;
00898
00899 for (arcptr = bb_graph[i].succ; arcptr;
00900 arcptr = arcptr->succ_next)
00901 if (! arcptr->count_valid)
00902 break;
00903 if (! arcptr)
00904 abort ();
00905 arcptr->count_valid = 1;
00906 arcptr->arc_count = total;
00907 bb_graph[i].succ_count--;
00908
00909 bb_graph[arcptr->target].pred_count--;
00910 changes = 1;
00911 }
00912 if (bb_graph[i].pred_count == 1)
00913 {
00914 total = 0;
00915
00916
00917 for (arcptr = bb_graph[i].pred; arcptr;
00918 arcptr = arcptr->pred_next)
00919 total += arcptr->arc_count;
00920
00921 total = bb_graph[i].exec_count - total;
00922
00923 for (arcptr = bb_graph[i].pred; arcptr;
00924 arcptr = arcptr->pred_next)
00925 if (! arcptr->count_valid)
00926 break;
00927 if (! arcptr)
00928 abort ();
00929 arcptr->count_valid = 1;
00930 arcptr->arc_count = total;
00931 bb_graph[i].pred_count--;
00932
00933 bb_graph[arcptr->source].succ_count--;
00934 changes = 1;
00935 }
00936 }
00937 }
00938 }
00939
00940
00941
00942 for (i = 0; i < num_blocks; i++)
00943 if (bb_graph[i].succ_count || bb_graph[i].pred_count)
00944 abort ();
00945 }
00946
00947
00948 static void
00949 read_files ()
00950 {
00951 struct stat buf;
00952 struct bb_info_list *list_end = 0;
00953 struct bb_info_list *b_ptr;
00954
00955 while (! feof (bbg_file))
00956 {
00957 b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
00958
00959 b_ptr->next = 0;
00960 if (list_end)
00961 list_end->next = b_ptr;
00962 else
00963 bb_graph_list = b_ptr;
00964 list_end = b_ptr;
00965
00966
00967
00968 create_program_flow_graph (b_ptr);
00969
00970
00971 ungetc (getc (bbg_file), bbg_file);
00972 }
00973
00974
00975
00976
00977 for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
00978 solve_program_flow_graph (b_ptr);
00979
00980
00981
00982 stat (bb_file_name, &buf);
00983 bb_data_size = buf.st_size / 4;
00984
00985 bb_data = (char *) xmalloc ((unsigned) buf.st_size);
00986 fread (bb_data, sizeof (char), buf.st_size, bb_file);
00987
00988 fclose (bb_file);
00989 if (da_file)
00990 fclose (da_file);
00991 fclose (bbg_file);
00992 }
00993
00994
00995
00996
00997
00998 static void
00999 scan_for_source_files ()
01000 {
01001 struct sourcefile *s_ptr = NULL;
01002 char *ptr;
01003 long count;
01004 long line_num;
01005
01006
01007
01008
01009
01010 ptr = bb_data;
01011 sources = 0;
01012 for (count = 0; count < bb_data_size; count++)
01013 {
01014 __fetch_long (&line_num, ptr, 4);
01015 ptr += 4;
01016 if (line_num == -1)
01017 {
01018
01019
01020 s_ptr = sources;
01021 while (s_ptr && strcmp (s_ptr->name, ptr))
01022 s_ptr = s_ptr->next;
01023
01024 if (s_ptr == 0)
01025 {
01026
01027
01028 s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
01029 s_ptr->name = xstrdup (ptr);
01030 s_ptr->maxlineno = 0;
01031 s_ptr->next = sources;
01032 sources = s_ptr;
01033 }
01034
01035
01036 {
01037 long delim;
01038 do {
01039 count++;
01040 __fetch_long (&delim, ptr, 4);
01041 ptr += 4;
01042 } while (delim != line_num);
01043 }
01044 }
01045 else if (line_num == -2)
01046 {
01047 long delim;
01048
01049
01050 do {
01051 count++;
01052 __fetch_long (&delim, ptr, 4);
01053 ptr += 4;
01054 } while (delim != line_num);
01055 }
01056
01057
01058
01059 else if (line_num > 0)
01060 {
01061 if (s_ptr->maxlineno <= line_num)
01062 s_ptr->maxlineno = line_num + 1;
01063 }
01064 else if (line_num < 0)
01065 {
01066
01067 abort ();
01068 }
01069 }
01070 }
01071
01072
01073
01074
01075 static void
01076 accumulate_branch_counts (function, a_ptr)
01077 struct coverage *function;
01078 struct arcdata *a_ptr;
01079 {
01080 if (a_ptr->call_insn)
01081 {
01082 function->calls++;
01083 if (a_ptr->total)
01084 function->calls_executed++;
01085 }
01086 else
01087 {
01088 function->branches++;
01089 if (a_ptr->total)
01090 function->branches_executed++;
01091 if (a_ptr->hits)
01092 function->branches_taken++;
01093 }
01094 }
01095
01096
01097
01098
01099 static void
01100 calculate_branch_probs (block_ptr, line_info, function)
01101 struct bb_info *block_ptr;
01102 struct line_info *line_info;
01103 struct coverage *function;
01104 {
01105 gcov_type total;
01106 struct adj_list *arcptr;
01107
01108 total = block_ptr->exec_count;
01109 for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
01110 {
01111 struct arcdata *a_ptr;
01112
01113
01114 if (arcptr->fall_through)
01115 continue;
01116
01117 a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
01118 a_ptr->total = total;
01119 a_ptr->hits = total ? arcptr->arc_count : 0;
01120 a_ptr->call_insn = arcptr->fake;
01121
01122 if (function)
01123 accumulate_branch_counts (function, a_ptr);
01124
01125 a_ptr->next = line_info->branches;
01126 line_info->branches = a_ptr;
01127 }
01128 }
01129
01130
01131
01132
01133
01134
01135
01136 static char const *
01137 format_hwint (top, bottom, dp)
01138 HOST_WIDEST_INT top, bottom;
01139 int dp;
01140 {
01141 static char buffer[20];
01142
01143 if (dp >= 0)
01144 {
01145 float ratio = bottom ? (float)top / bottom : 0;
01146 int ix;
01147 unsigned limit = 100;
01148 unsigned percent;
01149
01150 for (ix = dp; ix--; )
01151 limit *= 10;
01152
01153 percent = (unsigned) (ratio * limit + (float)0.5);
01154 if (percent <= 0 && top)
01155 percent = 1;
01156 else if (percent >= limit && top != bottom)
01157 percent = limit - 1;
01158 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
01159 if (dp)
01160 {
01161 dp++;
01162 do
01163 {
01164 buffer[ix+1] = buffer[ix];
01165 ix--;
01166 }
01167 while (dp--);
01168 buffer[ix + 1] = '.';
01169 }
01170 }
01171 else
01172 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
01173
01174 return buffer;
01175 }
01176
01177
01178
01179
01180 static void
01181 function_summary (function, title)
01182 struct coverage *function;
01183 const char *title;
01184 {
01185 if (function->lines)
01186 fnotice (stdout, "%s of %d lines executed in %s %s\n",
01187 format_hwint (function->lines_executed,
01188 function->lines, 2),
01189 function->lines, title, function->name);
01190 else
01191 fnotice (stdout, "No executable lines in %s %s\n",
01192 title, function->name);
01193
01194 if (output_branch_probs)
01195 {
01196 if (function->branches)
01197 {
01198 fnotice (stdout, "%s of %d branches executed in %s %s\n",
01199 format_hwint (function->branches_executed,
01200 function->branches, 2),
01201 function->branches, title, function->name);
01202 fnotice (stdout,
01203 "%s of %d branches taken at least once in %s %s\n",
01204 format_hwint (function->branches_taken,
01205 function->branches, 2),
01206 function->branches, title, function->name);
01207 }
01208 else
01209 fnotice (stdout, "No branches in %s %s\n", title, function->name);
01210 if (function->calls)
01211 fnotice (stdout, "%s of %d calls executed in %s %s\n",
01212 format_hwint (function->calls_executed,
01213 function->calls, 2),
01214 function->calls, title, function->name);
01215 else
01216 fnotice (stdout, "No calls in %s %s\n", title, function->name);
01217 }
01218 }
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 static char *
01231 make_gcov_file_name (src_name)
01232 char *src_name;
01233 {
01234 char *cptr;
01235 char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
01236
01237 name[0] = 0;
01238 if (output_long_names && strcmp (src_name, input_file_name))
01239 {
01240
01241 cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
01242 cptr = cptr ? cptr + 1 : input_file_name;
01243 strcat (name, cptr);
01244 strcat (name, "##");
01245 }
01246
01247
01248 cptr = preserve_paths ? NULL : strrchr (src_name, '/');
01249 cptr = cptr ? cptr + 1 : src_name;
01250 strcat (name, cptr);
01251
01252 if (preserve_paths)
01253 {
01254
01255 char *prev;
01256
01257 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
01258 {
01259 unsigned shift = 0;
01260
01261 if (prev + 1 == cptr && prev[0] == '.')
01262 {
01263
01264 shift = 2;
01265 }
01266 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
01267 {
01268
01269 shift = 1;
01270 prev[1] = '^';
01271 }
01272 else
01273 *cptr++ = '#';
01274 if (shift)
01275 {
01276 cptr = prev;
01277 do
01278 prev[0] = prev[shift];
01279 while (*prev++);
01280 }
01281 }
01282 }
01283
01284
01285
01286
01287 strcat (name, ".gcov");
01288 return name;
01289 }
01290
01291
01292
01293
01294
01295
01296 static void
01297 init_line_info (line_info, total, maxlineno)
01298 struct line_info *line_info;
01299 struct coverage *total;
01300 long maxlineno;
01301 {
01302 long block_num = 0;
01303 struct bb_info *block_ptr = NULL;
01304 struct coverage function;
01305 struct coverage *func_ptr = NULL;
01306 struct bb_info_list *current_graph = NULL;
01307 int is_this_file = 0;
01308 char *ptr = bb_data;
01309 long count;
01310 long line_num;
01311 struct line_info *line_ptr = 0;
01312
01313 memset (&function, 0, sizeof (function));
01314 if (output_function_summary)
01315 func_ptr = &function;
01316
01317 for (count = 0; count < bb_data_size; count++)
01318 {
01319 __fetch_long (&line_num, ptr, 4);
01320 ptr += 4;
01321 if (line_num < 0)
01322 {
01323 long delim;
01324
01325 if (line_num == -1)
01326 {
01327
01328
01329
01330 is_this_file = !strcmp (total->name, ptr);
01331 }
01332 else if (line_num == -2)
01333 {
01334
01335
01336 if (!current_graph)
01337 current_graph = bb_graph_list;
01338 else
01339 {
01340 if (block_num == current_graph->num_blocks - 1)
01341
01342 ;
01343 else if (block_num == current_graph->num_blocks - 2)
01344 {
01345 if (output_branch_probs && is_this_file)
01346 calculate_branch_probs (block_ptr, line_ptr, func_ptr);
01347 }
01348 else
01349 {
01350 fnotice (stderr,
01351 "didn't use all bb entries of graph, function %s\n",
01352 function.name);
01353 fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
01354 block_num, current_graph->num_blocks);
01355 }
01356 if (func_ptr && is_this_file)
01357 function_summary (func_ptr, "function");
01358 current_graph = current_graph->next;
01359 }
01360 block_num = 0;
01361 block_ptr = current_graph->bb_graph;
01362 memset (&function, 0, sizeof (function));
01363 function.name = ptr;
01364 }
01365 else
01366 {
01367 fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
01368 abort ();
01369 }
01370
01371
01372 for (delim = 0; delim != line_num; count++)
01373 {
01374 __fetch_long (&delim, ptr, 4);
01375 ptr += 4;
01376 }
01377 }
01378 else if (!line_num)
01379 {
01380
01381 if (block_num >= current_graph->num_blocks)
01382 {
01383 fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
01384 function.name);
01385 abort ();
01386 }
01387
01388 if (output_branch_probs && is_this_file)
01389 calculate_branch_probs (block_ptr, line_ptr, func_ptr);
01390
01391 block_num++;
01392 block_ptr++;
01393 }
01394 else if (is_this_file)
01395 {
01396 if (line_num >= maxlineno)
01397 {
01398 fnotice (stderr, "ERROR: out of range line number in function %s\n",
01399 function.name);
01400 abort ();
01401 }
01402
01403 line_ptr = &line_info[line_num];
01404 if (func_ptr)
01405 {
01406 if (!line_ptr->exists)
01407 func_ptr->lines++;
01408 if (!line_ptr->count && block_ptr->exec_count)
01409 func_ptr->lines_executed++;
01410 }
01411
01412
01413 line_ptr->count += block_ptr->exec_count;
01414 line_ptr->exists = 1;
01415 }
01416 }
01417
01418 if (func_ptr && is_this_file)
01419 function_summary (func_ptr, "function");
01420
01421
01422 for (line_num = 1, line_ptr = &line_info[line_num];
01423 line_num < maxlineno; line_num++, line_ptr++)
01424 {
01425 struct arcdata *a_ptr, *prev, *next;
01426
01427 if (line_ptr->exists)
01428 {
01429 total->lines++;
01430 if (line_ptr->count)
01431 total->lines_executed++;
01432 }
01433
01434
01435 for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
01436 {
01437 next = a_ptr->next;
01438 a_ptr->next = prev;
01439 prev = a_ptr;
01440
01441 accumulate_branch_counts (total, a_ptr);
01442 }
01443 line_ptr->branches = prev;
01444 }
01445 }
01446
01447
01448
01449
01450
01451 static void
01452 output_line_info (gcov_file, line_info, total, maxlineno)
01453 FILE *gcov_file;
01454 const struct line_info *line_info;
01455 const struct coverage *total;
01456 long maxlineno;
01457 {
01458 FILE *source_file;
01459 long line_num;
01460 const struct line_info *line_ptr;
01461 char string[STRING_SIZE];
01462 char const *retval = "";
01463
01464 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
01465 fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
01466
01467 source_file = fopen (total->name, "r");
01468 if (!source_file)
01469 {
01470 fnotice (stderr, "Could not open source file %s.\n", total->name);
01471 retval = NULL;
01472 }
01473 else
01474 {
01475 struct stat status;
01476
01477 if (!fstat (fileno (source_file), &status)
01478 && status.st_mtime > bb_file_time)
01479 {
01480 fnotice (stderr, "Warning: source file %s is newer than %s\n",
01481 total->name, bb_file_name);
01482 fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
01483 "-", 0);
01484 }
01485 }
01486
01487 for (line_num = 1, line_ptr = &line_info[line_num];
01488 line_num < maxlineno; line_num++, line_ptr++)
01489 {
01490
01491
01492
01493
01494
01495
01496 fprintf (gcov_file, "%9s:%5ld:",
01497 !line_ptr->exists ? "-"
01498 : !line_ptr->count ? "#####"
01499 : format_hwint (line_ptr->count, 0, -1), line_num);
01500
01501 if (retval)
01502 {
01503
01504 do
01505 {
01506 retval = fgets (string, STRING_SIZE, source_file);
01507 if (!retval)
01508 {
01509 fnotice (stderr,
01510 "Unexpected EOF while reading source file %s.\n",
01511 total->name);
01512 break;
01513 }
01514 fputs (retval, gcov_file);
01515 }
01516 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
01517 }
01518 if (!retval)
01519 fputs ("??\n", gcov_file);
01520
01521 if (output_branch_probs)
01522 {
01523 int i;
01524 struct arcdata *a_ptr;
01525
01526 for (i = 0, a_ptr = line_ptr->branches; a_ptr;
01527 a_ptr = a_ptr->next, i++)
01528 {
01529 if (a_ptr->call_insn)
01530 {
01531 if (a_ptr->total == 0)
01532 fnotice (gcov_file, "call %2d never executed\n", i);
01533 else
01534 fnotice
01535 (gcov_file, "call %2d returns %s\n", i,
01536 format_hwint (a_ptr->total - a_ptr->hits,
01537 a_ptr->total,
01538 -output_branch_counts));
01539 }
01540 else
01541 {
01542 if (a_ptr->total == 0)
01543 fnotice (gcov_file, "branch %2d never executed\n", i);
01544 else
01545 fnotice
01546 (gcov_file, "branch %2d taken %s\n", i,
01547 format_hwint (a_ptr->hits, a_ptr->total,
01548 -output_branch_counts));
01549 }
01550 }
01551 }
01552 }
01553
01554
01555
01556 if (retval)
01557 {
01558 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
01559 {
01560 fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
01561
01562 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
01563 {
01564 retval = fgets (string, STRING_SIZE, source_file);
01565 if (!retval)
01566 break;
01567 fputs (retval, gcov_file);
01568 }
01569 }
01570 }
01571
01572 if (source_file)
01573 fclose (source_file);
01574 }
01575
01576
01577
01578
01579
01580
01581
01582
01583 static void
01584 output_data (s_ptr)
01585 struct sourcefile *s_ptr;
01586 {
01587 struct line_info *line_info
01588 = (struct line_info *) xcalloc (s_ptr->maxlineno,
01589 sizeof (struct line_info));
01590 long line_num;
01591 struct coverage total;
01592
01593 memset (&total, 0, sizeof (total));
01594 total.name = s_ptr->name;
01595
01596 init_line_info (line_info, &total, s_ptr->maxlineno);
01597 function_summary (&total, "file");
01598
01599 if (output_gcov_file)
01600 {
01601
01602
01603
01604
01605 char *gcov_file_name = make_gcov_file_name (total.name);
01606 FILE *gcov_file = fopen (gcov_file_name, "w");
01607
01608 if (gcov_file)
01609 {
01610 fnotice (stdout, "Creating %s.\n", gcov_file_name);
01611 output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
01612 if (ferror (gcov_file))
01613 fnotice (stderr, "Error writing output file %s.\n",
01614 gcov_file_name);
01615 fclose (gcov_file);
01616 }
01617 else
01618 fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
01619 free (gcov_file_name);
01620 }
01621
01622
01623 for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
01624 {
01625 struct arcdata *branch, *next;
01626
01627 for (branch = line_info[line_num].branches; branch; branch = next)
01628 {
01629 next = branch->next;
01630 free (branch);
01631 }
01632 }
01633 free (line_info);
01634 }