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 #include "config.h"
00045 #include "system.h"
00046 #include "coretypes.h"
00047 #include "tm.h"
00048 #include "intl.h"
00049 #include "version.h"
00050
00051 #include <getopt.h>
00052
00053 #define IN_GCOV 1
00054 #include "gcov-io.h"
00055 #include "gcov-io.c"
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #define STRING_SIZE 200
00069
00070 struct function_info;
00071 struct block_info;
00072 struct source_info;
00073
00074
00075
00076 typedef struct arc_info
00077 {
00078
00079 struct block_info *src;
00080 struct block_info *dst;
00081
00082
00083 gcov_type count;
00084
00085 gcov_type cs_count;
00086
00087 unsigned int count_valid : 1;
00088 unsigned int on_tree : 1;
00089 unsigned int fake : 1;
00090 unsigned int fall_through : 1;
00091
00092
00093 unsigned int is_call_non_return : 1;
00094
00095
00096 unsigned int is_nonlocal_return : 1;
00097
00098
00099 unsigned int is_unconditional : 1;
00100
00101
00102 unsigned int cycle : 1;
00103
00104
00105 struct arc_info *line_next;
00106
00107
00108 struct arc_info *succ_next;
00109 struct arc_info *pred_next;
00110 } arc_t;
00111
00112
00113
00114
00115 typedef struct block_info
00116 {
00117
00118 arc_t *succ;
00119 arc_t *pred;
00120
00121
00122 gcov_type num_succ;
00123 gcov_type num_pred;
00124
00125
00126 gcov_type count;
00127 unsigned flags : 13;
00128 unsigned count_valid : 1;
00129 unsigned valid_chain : 1;
00130 unsigned invalid_chain : 1;
00131
00132
00133 unsigned is_call_site : 1;
00134 unsigned is_call_return : 1;
00135
00136
00137 unsigned is_nonlocal_return : 1;
00138
00139 union
00140 {
00141 struct
00142 {
00143
00144
00145
00146
00147 unsigned *encoding;
00148 unsigned num;
00149 } line;
00150 struct
00151 {
00152
00153
00154 arc_t *arc;
00155 unsigned ident;
00156 } cycle;
00157
00158 } u;
00159
00160
00161
00162 struct block_info *chain;
00163
00164 } block_t;
00165
00166
00167
00168 typedef struct function_info
00169 {
00170
00171 char *name;
00172 unsigned ident;
00173 unsigned checksum;
00174
00175
00176 block_t *blocks;
00177 unsigned num_blocks;
00178 unsigned blocks_executed;
00179
00180
00181 gcov_type *counts;
00182 unsigned num_counts;
00183
00184
00185 unsigned line;
00186 struct source_info *src;
00187
00188
00189 struct function_info *line_next;
00190
00191
00192 struct function_info *next;
00193 } function_t;
00194
00195
00196
00197 typedef struct coverage_info
00198 {
00199 int lines;
00200 int lines_executed;
00201
00202 int branches;
00203 int branches_executed;
00204 int branches_taken;
00205
00206 int calls;
00207 int calls_executed;
00208
00209 char *name;
00210 } coverage_t;
00211
00212
00213
00214
00215 typedef struct line_info
00216 {
00217 gcov_type count;
00218 union
00219 {
00220 arc_t *branches;
00221
00222
00223 block_t *blocks;
00224
00225 } u;
00226 unsigned exists : 1;
00227 } line_t;
00228
00229
00230
00231
00232 typedef struct source_info
00233 {
00234
00235 char *name;
00236 unsigned index;
00237
00238
00239 line_t *lines;
00240 unsigned num_lines;
00241
00242 coverage_t coverage;
00243
00244
00245
00246 function_t *functions;
00247
00248
00249 struct source_info *next;
00250 } source_t;
00251
00252
00253
00254 static function_t *functions;
00255
00256
00257
00258 static source_t *sources;
00259
00260
00261
00262 static struct gcov_summary object_summary;
00263 static unsigned program_count;
00264
00265
00266
00267 static time_t bbg_file_time;
00268
00269
00270
00271 static char *bbg_file_name;
00272
00273
00274 static unsigned bbg_stamp;
00275
00276
00277
00278 static char *da_file_name;
00279
00280
00281
00282 static int flag_branches = 0;
00283
00284
00285 static int flag_unconditional = 0;
00286
00287
00288
00289
00290 static int flag_gcov_file = 1;
00291
00292
00293
00294
00295
00296 static int flag_long_names = 0;
00297
00298
00299
00300
00301 static int flag_all_blocks = 0;
00302
00303
00304
00305 static int flag_function_summary = 0;
00306
00307
00308
00309
00310 static char *object_directory = 0;
00311
00312
00313
00314
00315
00316 static int flag_preserve_paths = 0;
00317
00318
00319
00320
00321 static int flag_counts = 0;
00322
00323
00324 static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
00325 static int process_args (int, char **);
00326 static void print_usage (int) ATTRIBUTE_NORETURN;
00327 static void print_version (void) ATTRIBUTE_NORETURN;
00328 static void process_file (const char *);
00329 static void create_file_names (const char *);
00330 static source_t *find_source (const char *);
00331 static int read_graph_file (void);
00332 static int read_count_file (void);
00333 static void solve_flow_graph (function_t *);
00334 static void add_branch_counts (coverage_t *, const arc_t *);
00335 static void add_line_counts (coverage_t *, function_t *);
00336 static void function_summary (const coverage_t *, const char *);
00337 static const char *format_gcov (gcov_type, gcov_type, int);
00338 static void accumulate_line_counts (source_t *);
00339 static int output_branch_count (FILE *, int, const arc_t *);
00340 static void output_lines (FILE *, const source_t *);
00341 static char *make_gcov_file_name (const char *, const char *);
00342 static void release_structures (void);
00343 extern int main (int, char **);
00344
00345 int
00346 main (int argc, char **argv)
00347 {
00348 int argno;
00349
00350
00351 unlock_std_streams ();
00352
00353 gcc_init_libintl ();
00354
00355 argno = process_args (argc, argv);
00356 if (optind == argc)
00357 print_usage (true);
00358
00359 for (; argno != argc; argno++)
00360 {
00361 release_structures ();
00362
00363 process_file (argv[argno]);
00364 }
00365
00366 return 0;
00367 }
00368
00369 static void
00370 fnotice (FILE *file, const char *cmsgid, ...)
00371 {
00372 va_list ap;
00373
00374 va_start (ap, cmsgid);
00375 vfprintf (file, _(cmsgid), ap);
00376 va_end (ap);
00377 }
00378
00379
00380
00381
00382 static void
00383 print_usage (int error_p)
00384 {
00385 FILE *file = error_p ? stderr : stdout;
00386 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
00387
00388 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
00389 fnotice (file, "Print code coverage information.\n\n");
00390 fnotice (file, " -h, --help Print this help, then exit\n");
00391 fnotice (file, " -v, --version Print version number, then exit\n");
00392 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
00393 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
00394 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
00395 rather than percentages\n");
00396 fnotice (file, " -n, --no-output Do not create an output file\n");
00397 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
00398 source files\n");
00399 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
00400 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
00401 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
00402 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
00403 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
00404 bug_report_url);
00405 exit (status);
00406 }
00407
00408
00409
00410 static void
00411 print_version (void)
00412 {
00413 fnotice (stdout, "gcov (GCC) %s\n", version_string);
00414 fprintf (stdout, "Copyright %s 2004 Free Software Foundation, Inc.\n",
00415 _("(C)"));
00416 fnotice (stdout,
00417 _("This is free software; see the source for copying conditions.\n"
00418 "There is NO warranty; not even for MERCHANTABILITY or \n"
00419 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
00420 exit (SUCCESS_EXIT_CODE);
00421 }
00422
00423 static const struct option options[] =
00424 {
00425 { "help", no_argument, NULL, 'h' },
00426 { "version", no_argument, NULL, 'v' },
00427 { "all-blocks", no_argument, NULL, 'a' },
00428 { "branch-probabilities", no_argument, NULL, 'b' },
00429 { "branch-counts", no_argument, NULL, 'c' },
00430 { "no-output", no_argument, NULL, 'n' },
00431 { "long-file-names", no_argument, NULL, 'l' },
00432 { "function-summaries", no_argument, NULL, 'f' },
00433 { "preserve-paths", no_argument, NULL, 'p' },
00434 { "object-directory", required_argument, NULL, 'o' },
00435 { "object-file", required_argument, NULL, 'o' },
00436 { "unconditional-branches", no_argument, NULL, 'u' },
00437 { 0, 0, 0, 0 }
00438 };
00439
00440
00441
00442 static int
00443 process_args (int argc, char **argv)
00444 {
00445 int opt;
00446
00447 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
00448 {
00449 switch (opt)
00450 {
00451 case 'a':
00452 flag_all_blocks = 1;
00453 break;
00454 case 'b':
00455 flag_branches = 1;
00456 break;
00457 case 'c':
00458 flag_counts = 1;
00459 break;
00460 case 'f':
00461 flag_function_summary = 1;
00462 break;
00463 case 'h':
00464 print_usage (false);
00465
00466 case 'l':
00467 flag_long_names = 1;
00468 break;
00469 case 'n':
00470 flag_gcov_file = 0;
00471 break;
00472 case 'o':
00473 object_directory = optarg;
00474 break;
00475 case 'p':
00476 flag_preserve_paths = 1;
00477 break;
00478 case 'u':
00479 flag_unconditional = 1;
00480 break;
00481 case 'v':
00482 print_version ();
00483
00484 default:
00485 print_usage (true);
00486
00487 }
00488 }
00489
00490 return optind;
00491 }
00492
00493
00494
00495 static void
00496 process_file (const char *file_name)
00497 {
00498 source_t *src;
00499 function_t *fn;
00500
00501 create_file_names (file_name);
00502 if (read_graph_file ())
00503 return;
00504
00505 if (!functions)
00506 {
00507 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
00508 return;
00509 }
00510
00511 if (read_count_file ())
00512 return;
00513
00514 for (fn = functions; fn; fn = fn->next)
00515 solve_flow_graph (fn);
00516 for (src = sources; src; src = src->next)
00517 src->lines = xcalloc (src->num_lines, sizeof (line_t));
00518 for (fn = functions; fn; fn = fn->next)
00519 {
00520 coverage_t coverage;
00521
00522 memset (&coverage, 0, sizeof (coverage));
00523 coverage.name = fn->name;
00524 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
00525 if (flag_function_summary)
00526 {
00527 function_summary (&coverage, "Function");
00528 fnotice (stdout, "\n");
00529 }
00530 }
00531
00532 for (src = sources; src; src = src->next)
00533 {
00534 accumulate_line_counts (src);
00535 function_summary (&src->coverage, "File");
00536 if (flag_gcov_file)
00537 {
00538 char *gcov_file_name = make_gcov_file_name (file_name, src->name);
00539 FILE *gcov_file = fopen (gcov_file_name, "w");
00540
00541 if (gcov_file)
00542 {
00543 fnotice (stdout, "%s:creating '%s'\n",
00544 src->name, gcov_file_name);
00545 output_lines (gcov_file, src);
00546 if (ferror (gcov_file))
00547 fnotice (stderr, "%s:error writing output file '%s'\n",
00548 src->name, gcov_file_name);
00549 fclose (gcov_file);
00550 }
00551 else
00552 fnotice (stderr, "%s:could not open output file '%s'\n",
00553 src->name, gcov_file_name);
00554 free (gcov_file_name);
00555 }
00556 fnotice (stdout, "\n");
00557 }
00558 }
00559
00560
00561
00562 static void
00563 release_structures (void)
00564 {
00565 function_t *fn;
00566 source_t *src;
00567
00568 free (bbg_file_name);
00569 free (da_file_name);
00570 da_file_name = bbg_file_name = NULL;
00571 bbg_file_time = 0;
00572 bbg_stamp = 0;
00573
00574 while ((src = sources))
00575 {
00576 sources = src->next;
00577
00578 free (src->name);
00579 free (src->lines);
00580 }
00581
00582 while ((fn = functions))
00583 {
00584 unsigned ix;
00585 block_t *block;
00586
00587 functions = fn->next;
00588 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
00589 {
00590 arc_t *arc, *arc_n;
00591
00592 for (arc = block->succ; arc; arc = arc_n)
00593 {
00594 arc_n = arc->succ_next;
00595 free (arc);
00596 }
00597 }
00598 free (fn->blocks);
00599 free (fn->counts);
00600 }
00601 }
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 static void
00612 create_file_names (const char *file_name)
00613 {
00614 char *cptr;
00615 char *name;
00616 int length = strlen (file_name);
00617 int base;
00618
00619 if (object_directory && object_directory[0])
00620 {
00621 struct stat status;
00622
00623 length += strlen (object_directory) + 2;
00624 name = xmalloc (length);
00625 name[0] = 0;
00626
00627 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
00628 strcat (name, object_directory);
00629 if (base && name[strlen (name) - 1] != '/')
00630 strcat (name, "/");
00631 }
00632 else
00633 {
00634 name = xmalloc (length + 1);
00635 name[0] = 0;
00636 base = 1;
00637 }
00638
00639 if (base)
00640 {
00641
00642 cptr = strrchr (file_name, '/');
00643 strcat (name, cptr ? cptr + 1 : file_name);
00644 }
00645
00646
00647 cptr = strrchr (name, '.');
00648 if (cptr)
00649 *cptr = 0;
00650
00651 length = strlen (name);
00652
00653 bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
00654 strcpy (bbg_file_name, name);
00655 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
00656
00657 da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
00658 strcpy (da_file_name, name);
00659 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
00660
00661 return;
00662 }
00663
00664
00665
00666
00667 static source_t *
00668 find_source (const char *file_name)
00669 {
00670 source_t *src;
00671
00672 if (!file_name)
00673 file_name = "<unknown>";
00674
00675 for (src = sources; src; src = src->next)
00676 if (!strcmp (file_name, src->name))
00677 return src;
00678
00679 src = xcalloc (1, sizeof (source_t));
00680 src->name = xstrdup (file_name);
00681 src->coverage.name = src->name;
00682 src->index = sources ? sources->index + 1 : 1;
00683 src->next = sources;
00684 sources = src;
00685
00686 return src;
00687 }
00688
00689
00690
00691 static int
00692 read_graph_file (void)
00693 {
00694 unsigned version;
00695 unsigned current_tag = 0;
00696 struct function_info *fn = NULL;
00697 source_t *src = NULL;
00698 unsigned ix;
00699 unsigned tag;
00700
00701 if (!gcov_open (bbg_file_name, 1))
00702 {
00703 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
00704 return 1;
00705 }
00706 bbg_file_time = gcov_time ();
00707 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
00708 {
00709 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
00710 gcov_close ();
00711 return 1;
00712 }
00713
00714 version = gcov_read_unsigned ();
00715 if (version != GCOV_VERSION)
00716 {
00717 char v[4], e[4];
00718
00719 GCOV_UNSIGNED2STRING (v, version);
00720 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
00721
00722 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
00723 bbg_file_name, v, e);
00724 }
00725 bbg_stamp = gcov_read_unsigned ();
00726
00727 while ((tag = gcov_read_unsigned ()))
00728 {
00729 unsigned length = gcov_read_unsigned ();
00730 gcov_position_t base = gcov_position ();
00731
00732 if (tag == GCOV_TAG_FUNCTION)
00733 {
00734 char *function_name;
00735 unsigned ident, checksum, lineno;
00736 source_t *src;
00737 function_t *probe, *prev;
00738
00739 ident = gcov_read_unsigned ();
00740 checksum = gcov_read_unsigned ();
00741 function_name = xstrdup (gcov_read_string ());
00742 src = find_source (gcov_read_string ());
00743 lineno = gcov_read_unsigned ();
00744
00745 fn = xcalloc (1, sizeof (function_t));
00746 fn->name = function_name;
00747 fn->ident = ident;
00748 fn->checksum = checksum;
00749 fn->src = src;
00750 fn->line = lineno;
00751
00752 fn->next = functions;
00753 functions = fn;
00754 current_tag = tag;
00755
00756 if (lineno >= src->num_lines)
00757 src->num_lines = lineno + 1;
00758
00759
00760
00761 for (probe = src->functions, prev = NULL;
00762 probe && probe->line > lineno;
00763 prev = probe, probe = probe->line_next)
00764 continue;
00765 fn->line_next = probe;
00766 if (prev)
00767 prev->line_next = fn;
00768 else
00769 src->functions = fn;
00770 }
00771 else if (fn && tag == GCOV_TAG_BLOCKS)
00772 {
00773 if (fn->blocks)
00774 fnotice (stderr, "%s:already seen blocks for '%s'\n",
00775 bbg_file_name, fn->name);
00776 else
00777 {
00778 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
00779 fn->num_blocks = num_blocks;
00780
00781 fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t));
00782 for (ix = 0; ix != num_blocks; ix++)
00783 fn->blocks[ix].flags = gcov_read_unsigned ();
00784 }
00785 }
00786 else if (fn && tag == GCOV_TAG_ARCS)
00787 {
00788 unsigned src = gcov_read_unsigned ();
00789 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
00790
00791 if (src >= fn->num_blocks || fn->blocks[src].succ)
00792 goto corrupt;
00793
00794 while (num_dests--)
00795 {
00796 struct arc_info *arc;
00797 unsigned dest = gcov_read_unsigned ();
00798 unsigned flags = gcov_read_unsigned ();
00799
00800 if (dest >= fn->num_blocks)
00801 goto corrupt;
00802 arc = xcalloc (1, sizeof (arc_t));
00803
00804 arc->dst = &fn->blocks[dest];
00805 arc->src = &fn->blocks[src];
00806
00807 arc->count = 0;
00808 arc->count_valid = 0;
00809 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
00810 arc->fake = !!(flags & GCOV_ARC_FAKE);
00811 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
00812
00813 arc->succ_next = fn->blocks[src].succ;
00814 fn->blocks[src].succ = arc;
00815 fn->blocks[src].num_succ++;
00816
00817 arc->pred_next = fn->blocks[dest].pred;
00818 fn->blocks[dest].pred = arc;
00819 fn->blocks[dest].num_pred++;
00820
00821 if (arc->fake)
00822 {
00823 if (src)
00824 {
00825
00826
00827 fn->blocks[src].is_call_site = 1;
00828 arc->is_call_non_return = 1;
00829 }
00830 else
00831 {
00832
00833
00834
00835 arc->is_nonlocal_return = 1;
00836 fn->blocks[dest].is_nonlocal_return = 1;
00837 }
00838 }
00839
00840 if (!arc->on_tree)
00841 fn->num_counts++;
00842 }
00843 }
00844 else if (fn && tag == GCOV_TAG_LINES)
00845 {
00846 unsigned blockno = gcov_read_unsigned ();
00847 unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned));
00848
00849 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
00850 goto corrupt;
00851
00852 for (ix = 0; ; )
00853 {
00854 unsigned lineno = gcov_read_unsigned ();
00855
00856 if (lineno)
00857 {
00858 if (!ix)
00859 {
00860 line_nos[ix++] = 0;
00861 line_nos[ix++] = src->index;
00862 }
00863 line_nos[ix++] = lineno;
00864 if (lineno >= src->num_lines)
00865 src->num_lines = lineno + 1;
00866 }
00867 else
00868 {
00869 const char *file_name = gcov_read_string ();
00870
00871 if (!file_name)
00872 break;
00873 src = find_source (file_name);
00874
00875 line_nos[ix++] = 0;
00876 line_nos[ix++] = src->index;
00877 }
00878 }
00879
00880 fn->blocks[blockno].u.line.encoding = line_nos;
00881 fn->blocks[blockno].u.line.num = ix;
00882 }
00883 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
00884 {
00885 fn = NULL;
00886 current_tag = 0;
00887 }
00888 gcov_sync (base, length);
00889 if (gcov_is_error ())
00890 {
00891 corrupt:;
00892 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
00893 gcov_close ();
00894 return 1;
00895 }
00896 }
00897 gcov_close ();
00898
00899
00900
00901
00902
00903 {
00904 source_t *src, *src_p, *src_n;
00905
00906 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
00907 {
00908 src_n = src->next;
00909 src->next = src_p;
00910 }
00911 sources = src_p;
00912 }
00913
00914
00915 {
00916 function_t *fn, *fn_p, *fn_n;
00917
00918 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
00919 {
00920 unsigned ix;
00921
00922 fn_n = fn->next;
00923 fn->next = fn_p;
00924
00925
00926 for (ix = fn->num_blocks; ix--;)
00927 {
00928 arc_t *arc, *arc_p, *arc_n;
00929
00930 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
00931 arc_p = arc, arc = arc_n)
00932 {
00933 arc_n = arc->succ_next;
00934 arc->succ_next = arc_p;
00935 }
00936 fn->blocks[ix].succ = arc_p;
00937
00938 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
00939 arc_p = arc, arc = arc_n)
00940 {
00941 arc_n = arc->pred_next;
00942 arc->pred_next = arc_p;
00943 }
00944 fn->blocks[ix].pred = arc_p;
00945 }
00946 }
00947 functions = fn_p;
00948 }
00949 return 0;
00950 }
00951
00952
00953
00954
00955 static int
00956 read_count_file (void)
00957 {
00958 unsigned ix;
00959 unsigned version;
00960 unsigned tag;
00961 function_t *fn = NULL;
00962 int error = 0;
00963
00964 if (!gcov_open (da_file_name, 1))
00965 {
00966 fnotice (stderr, "%s:cannot open data file\n", da_file_name);
00967 return 1;
00968 }
00969 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
00970 {
00971 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
00972 cleanup:;
00973 gcov_close ();
00974 return 1;
00975 }
00976 version = gcov_read_unsigned ();
00977 if (version != GCOV_VERSION)
00978 {
00979 char v[4], e[4];
00980
00981 GCOV_UNSIGNED2STRING (v, version);
00982 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
00983
00984 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
00985 da_file_name, v, e);
00986 }
00987 tag = gcov_read_unsigned ();
00988 if (tag != bbg_stamp)
00989 {
00990 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
00991 goto cleanup;
00992 }
00993
00994 while ((tag = gcov_read_unsigned ()))
00995 {
00996 unsigned length = gcov_read_unsigned ();
00997 unsigned long base = gcov_position ();
00998
00999 if (tag == GCOV_TAG_OBJECT_SUMMARY)
01000 gcov_read_summary (&object_summary);
01001 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
01002 program_count++;
01003 else if (tag == GCOV_TAG_FUNCTION)
01004 {
01005 unsigned ident = gcov_read_unsigned ();
01006 struct function_info *fn_n = functions;
01007
01008 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
01009 {
01010 if (fn)
01011 ;
01012 else if ((fn = fn_n))
01013 fn_n = NULL;
01014 else
01015 {
01016 fnotice (stderr, "%s:unknown function '%u'\n",
01017 da_file_name, ident);
01018 break;
01019 }
01020 if (fn->ident == ident)
01021 break;
01022 }
01023
01024 if (!fn)
01025 ;
01026 else if (gcov_read_unsigned () != fn->checksum)
01027 {
01028 mismatch:;
01029 fnotice (stderr, "%s:profile mismatch for '%s'\n",
01030 da_file_name, fn->name);
01031 goto cleanup;
01032 }
01033 }
01034 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
01035 {
01036 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
01037 goto mismatch;
01038
01039 if (!fn->counts)
01040 fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type));
01041
01042 for (ix = 0; ix != fn->num_counts; ix++)
01043 fn->counts[ix] += gcov_read_counter ();
01044 }
01045 gcov_sync (base, length);
01046 if ((error = gcov_is_error ()))
01047 {
01048 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
01049 da_file_name);
01050 goto cleanup;
01051 }
01052 }
01053
01054 gcov_close ();
01055 return 0;
01056 }
01057
01058
01059
01060
01061 static void
01062 solve_flow_graph (function_t *fn)
01063 {
01064 unsigned ix;
01065 arc_t *arc;
01066 gcov_type *count_ptr = fn->counts;
01067 block_t *blk;
01068 block_t *valid_blocks = NULL;
01069 block_t *invalid_blocks = NULL;
01070
01071 if (fn->num_blocks < 2)
01072 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
01073 bbg_file_name, fn->name);
01074 else
01075 {
01076 if (fn->blocks[0].num_pred)
01077 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
01078 bbg_file_name, fn->name);
01079 else
01080
01081
01082 fn->blocks[0].num_pred = ~(unsigned)0;
01083
01084 if (fn->blocks[fn->num_blocks - 1].num_succ)
01085 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
01086 bbg_file_name, fn->name);
01087 else
01088
01089
01090 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
01091 }
01092
01093
01094
01095 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
01096 {
01097 block_t const *prev_dst = NULL;
01098 int out_of_order = 0;
01099 int non_fake_succ = 0;
01100
01101 for (arc = blk->succ; arc; arc = arc->succ_next)
01102 {
01103 if (!arc->fake)
01104 non_fake_succ++;
01105
01106 if (!arc->on_tree)
01107 {
01108 if (count_ptr)
01109 arc->count = *count_ptr++;
01110 arc->count_valid = 1;
01111 blk->num_succ--;
01112 arc->dst->num_pred--;
01113 }
01114 if (prev_dst && prev_dst > arc->dst)
01115 out_of_order = 1;
01116 prev_dst = arc->dst;
01117 }
01118 if (non_fake_succ == 1)
01119 {
01120
01121
01122 for (arc = blk->succ; arc; arc = arc->succ_next)
01123 if (!arc->fake)
01124 {
01125 arc->is_unconditional = 1;
01126
01127
01128
01129
01130
01131
01132 if (blk->is_call_site && arc->fall_through
01133 && arc->dst->pred == arc && !arc->pred_next)
01134 arc->dst->is_call_return = 1;
01135 }
01136 }
01137
01138
01139
01140
01141
01142 if (out_of_order)
01143 {
01144 arc_t *start = blk->succ;
01145 unsigned changes = 1;
01146
01147 while (changes)
01148 {
01149 arc_t *arc, *arc_p, *arc_n;
01150
01151 changes = 0;
01152 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
01153 {
01154 if (arc->dst > arc_n->dst)
01155 {
01156 changes = 1;
01157 if (arc_p)
01158 arc_p->succ_next = arc_n;
01159 else
01160 start = arc_n;
01161 arc->succ_next = arc_n->succ_next;
01162 arc_n->succ_next = arc;
01163 arc_p = arc_n;
01164 }
01165 else
01166 {
01167 arc_p = arc;
01168 arc = arc_n;
01169 }
01170 }
01171 }
01172 blk->succ = start;
01173 }
01174
01175
01176
01177 blk->invalid_chain = 1;
01178 blk->chain = invalid_blocks;
01179 invalid_blocks = blk;
01180 }
01181
01182 while (invalid_blocks || valid_blocks)
01183 {
01184 while ((blk = invalid_blocks))
01185 {
01186 gcov_type total = 0;
01187 const arc_t *arc;
01188
01189 invalid_blocks = blk->chain;
01190 blk->invalid_chain = 0;
01191 if (!blk->num_succ)
01192 for (arc = blk->succ; arc; arc = arc->succ_next)
01193 total += arc->count;
01194 else if (!blk->num_pred)
01195 for (arc = blk->pred; arc; arc = arc->pred_next)
01196 total += arc->count;
01197 else
01198 continue;
01199
01200 blk->count = total;
01201 blk->count_valid = 1;
01202 blk->chain = valid_blocks;
01203 blk->valid_chain = 1;
01204 valid_blocks = blk;
01205 }
01206 while ((blk = valid_blocks))
01207 {
01208 gcov_type total;
01209 arc_t *arc, *inv_arc;
01210
01211 valid_blocks = blk->chain;
01212 blk->valid_chain = 0;
01213 if (blk->num_succ == 1)
01214 {
01215 block_t *dst;
01216
01217 total = blk->count;
01218 inv_arc = NULL;
01219 for (arc = blk->succ; arc; arc = arc->succ_next)
01220 {
01221 total -= arc->count;
01222 if (!arc->count_valid)
01223 inv_arc = arc;
01224 }
01225 dst = inv_arc->dst;
01226 inv_arc->count_valid = 1;
01227 inv_arc->count = total;
01228 blk->num_succ--;
01229 dst->num_pred--;
01230 if (dst->count_valid)
01231 {
01232 if (dst->num_pred == 1 && !dst->valid_chain)
01233 {
01234 dst->chain = valid_blocks;
01235 dst->valid_chain = 1;
01236 valid_blocks = dst;
01237 }
01238 }
01239 else
01240 {
01241 if (!dst->num_pred && !dst->invalid_chain)
01242 {
01243 dst->chain = invalid_blocks;
01244 dst->invalid_chain = 1;
01245 invalid_blocks = dst;
01246 }
01247 }
01248 }
01249 if (blk->num_pred == 1)
01250 {
01251 block_t *src;
01252
01253 total = blk->count;
01254 inv_arc = NULL;
01255 for (arc = blk->pred; arc; arc = arc->pred_next)
01256 {
01257 total -= arc->count;
01258 if (!arc->count_valid)
01259 inv_arc = arc;
01260 }
01261 src = inv_arc->src;
01262 inv_arc->count_valid = 1;
01263 inv_arc->count = total;
01264 blk->num_pred--;
01265 src->num_succ--;
01266 if (src->count_valid)
01267 {
01268 if (src->num_succ == 1 && !src->valid_chain)
01269 {
01270 src->chain = valid_blocks;
01271 src->valid_chain = 1;
01272 valid_blocks = src;
01273 }
01274 }
01275 else
01276 {
01277 if (!src->num_succ && !src->invalid_chain)
01278 {
01279 src->chain = invalid_blocks;
01280 src->invalid_chain = 1;
01281 invalid_blocks = src;
01282 }
01283 }
01284 }
01285 }
01286 }
01287
01288
01289
01290 for (ix = 0; ix < fn->num_blocks; ix++)
01291 if (!fn->blocks[ix].count_valid)
01292 {
01293 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
01294 bbg_file_name, fn->name);
01295 break;
01296 }
01297 }
01298
01299
01300
01301
01302
01303 static void
01304 add_branch_counts (coverage_t *coverage, const arc_t *arc)
01305 {
01306 if (arc->is_call_non_return)
01307 {
01308 coverage->calls++;
01309 if (arc->src->count)
01310 coverage->calls_executed++;
01311 }
01312 else if (!arc->is_unconditional)
01313 {
01314 coverage->branches++;
01315 if (arc->src->count)
01316 coverage->branches_executed++;
01317 if (arc->count)
01318 coverage->branches_taken++;
01319 }
01320 }
01321
01322
01323
01324
01325
01326
01327
01328 static char const *
01329 format_gcov (gcov_type top, gcov_type bottom, int dp)
01330 {
01331 static char buffer[20];
01332
01333 if (dp >= 0)
01334 {
01335 float ratio = bottom ? (float)top / bottom : 0;
01336 int ix;
01337 unsigned limit = 100;
01338 unsigned percent;
01339
01340 for (ix = dp; ix--; )
01341 limit *= 10;
01342
01343 percent = (unsigned) (ratio * limit + (float)0.5);
01344 if (percent <= 0 && top)
01345 percent = 1;
01346 else if (percent >= limit && top != bottom)
01347 percent = limit - 1;
01348 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
01349 if (dp)
01350 {
01351 dp++;
01352 do
01353 {
01354 buffer[ix+1] = buffer[ix];
01355 ix--;
01356 }
01357 while (dp--);
01358 buffer[ix + 1] = '.';
01359 }
01360 }
01361 else
01362 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
01363
01364 return buffer;
01365 }
01366
01367
01368
01369
01370 static void
01371 function_summary (const coverage_t *coverage, const char *title)
01372 {
01373 fnotice (stdout, "%s '%s'\n", title, coverage->name);
01374
01375 if (coverage->lines)
01376 fnotice (stdout, "Lines executed:%s of %d\n",
01377 format_gcov (coverage->lines_executed, coverage->lines, 2),
01378 coverage->lines);
01379 else
01380 fnotice (stdout, "No executable lines\n");
01381
01382 if (flag_branches)
01383 {
01384 if (coverage->branches)
01385 {
01386 fnotice (stdout, "Branches executed:%s of %d\n",
01387 format_gcov (coverage->branches_executed,
01388 coverage->branches, 2),
01389 coverage->branches);
01390 fnotice (stdout, "Taken at least once:%s of %d\n",
01391 format_gcov (coverage->branches_taken,
01392 coverage->branches, 2),
01393 coverage->branches);
01394 }
01395 else
01396 fnotice (stdout, "No branches\n");
01397 if (coverage->calls)
01398 fnotice (stdout, "Calls executed:%s of %d\n",
01399 format_gcov (coverage->calls_executed, coverage->calls, 2),
01400 coverage->calls);
01401 else
01402 fnotice (stdout, "No calls\n");
01403 }
01404 }
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416 static char *
01417 make_gcov_file_name (const char *input_name, const char *src_name)
01418 {
01419 char *cptr;
01420 char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10);
01421
01422 name[0] = 0;
01423 if (flag_long_names && strcmp (src_name, input_name))
01424 {
01425
01426 cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
01427 strcat (name, cptr ? cptr + 1 : input_name);
01428 strcat (name, "##");
01429 }
01430
01431
01432 cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
01433 strcat (name, cptr ? cptr + 1 : src_name);
01434
01435 if (flag_preserve_paths)
01436 {
01437
01438 char *prev;
01439
01440 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
01441 {
01442 unsigned shift = 0;
01443
01444 if (prev + 1 == cptr && prev[0] == '.')
01445 {
01446
01447 shift = 2;
01448 }
01449 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
01450 {
01451
01452 shift = 1;
01453 prev[1] = '^';
01454 }
01455 else
01456 *cptr++ = '#';
01457 if (shift)
01458 {
01459 cptr = prev;
01460 do
01461 prev[0] = prev[shift];
01462 while (*prev++);
01463 }
01464 }
01465 }
01466
01467 strcat (name, ".gcov");
01468 return name;
01469 }
01470
01471
01472
01473
01474
01475 static void
01476 add_line_counts (coverage_t *coverage, function_t *fn)
01477 {
01478 unsigned ix;
01479 line_t *line = NULL;
01480
01481
01482
01483 for (ix = 0; ix != fn->num_blocks; ix++)
01484 {
01485 block_t *block = &fn->blocks[ix];
01486 unsigned *encoding;
01487 const source_t *src = NULL;
01488 unsigned jx;
01489
01490 if (block->count && ix && ix + 1 != fn->num_blocks)
01491 fn->blocks_executed++;
01492 for (jx = 0, encoding = block->u.line.encoding;
01493 jx != block->u.line.num; jx++, encoding++)
01494 if (!*encoding)
01495 {
01496 unsigned src_n = *++encoding;
01497
01498 for (src = sources; src->index != src_n; src = src->next)
01499 continue;
01500 jx++;
01501 }
01502 else
01503 {
01504 line = &src->lines[*encoding];
01505
01506 if (coverage)
01507 {
01508 if (!line->exists)
01509 coverage->lines++;
01510 if (!line->count && block->count)
01511 coverage->lines_executed++;
01512 }
01513 line->exists = 1;
01514 line->count += block->count;
01515 }
01516 free (block->u.line.encoding);
01517 block->u.cycle.arc = NULL;
01518 block->u.cycle.ident = ~0U;
01519
01520 if (!ix || ix + 1 == fn->num_blocks)
01521 ;
01522 else if (flag_all_blocks)
01523 {
01524 line_t *block_line = line ? line : &fn->src->lines[fn->line];
01525
01526 block->chain = block_line->u.blocks;
01527 block_line->u.blocks = block;
01528 }
01529 else if (flag_branches)
01530 {
01531 arc_t *arc;
01532
01533 for (arc = block->succ; arc; arc = arc->succ_next)
01534 {
01535 arc->line_next = line->u.branches;
01536 line->u.branches = arc;
01537 if (coverage && !arc->is_unconditional)
01538 add_branch_counts (coverage, arc);
01539 }
01540 }
01541 }
01542 if (!line)
01543 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
01544 }
01545
01546
01547
01548 static void
01549 accumulate_line_counts (source_t *src)
01550 {
01551 line_t *line;
01552 function_t *fn, *fn_p, *fn_n;
01553 unsigned ix;
01554
01555
01556 for (fn = src->functions, fn_p = NULL; fn;
01557 fn_p = fn, fn = fn_n)
01558 {
01559 fn_n = fn->line_next;
01560 fn->line_next = fn_p;
01561 }
01562 src->functions = fn_p;
01563
01564 for (ix = src->num_lines, line = src->lines; ix--; line++)
01565 {
01566 if (!flag_all_blocks)
01567 {
01568 arc_t *arc, *arc_p, *arc_n;
01569
01570
01571 for (arc = line->u.branches, arc_p = NULL; arc;
01572 arc_p = arc, arc = arc_n)
01573 {
01574 arc_n = arc->line_next;
01575 arc->line_next = arc_p;
01576
01577 add_branch_counts (&src->coverage, arc);
01578 }
01579 line->u.branches = arc_p;
01580 }
01581 else if (line->u.blocks)
01582 {
01583
01584
01585
01586
01587
01588
01589 block_t *block, *block_p, *block_n;
01590 gcov_type count = 0;
01591
01592
01593 for (block = line->u.blocks, block_p = NULL; block;
01594 block_p = block, block = block_n)
01595 {
01596 block_n = block->chain;
01597 block->chain = block_p;
01598 block->u.cycle.ident = ix;
01599 }
01600 line->u.blocks = block_p;
01601
01602
01603 for (block = line->u.blocks; block; block = block->chain)
01604 {
01605 arc_t *arc;
01606
01607 for (arc = block->pred; arc; arc = arc->pred_next)
01608 {
01609 if (arc->src->u.cycle.ident != ix)
01610 count += arc->count;
01611 if (flag_branches)
01612 add_branch_counts (&src->coverage, arc);
01613 }
01614
01615
01616 for (arc = block->succ; arc; arc = arc->succ_next)
01617 arc->cs_count = arc->count;
01618 }
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636 for (block = line->u.blocks; block; block = block->chain)
01637 {
01638 block_t *head = block;
01639 arc_t *arc;
01640
01641 next_vertex:;
01642 arc = head->succ;
01643 current_vertex:;
01644 while (arc)
01645 {
01646 block_t *dst = arc->dst;
01647 if (
01648 arc->cycle
01649
01650 || dst->u.cycle.ident != ix
01651
01652 || dst->u.cycle.arc)
01653 {
01654 arc = arc->succ_next;
01655 continue;
01656 }
01657
01658 if (dst == block)
01659 {
01660
01661 gcov_type cycle_count = arc->cs_count;
01662 arc_t *cycle_arc = arc;
01663 arc_t *probe_arc;
01664
01665
01666 for (dst = head; (probe_arc = dst->u.cycle.arc);
01667 dst = probe_arc->src)
01668 if (cycle_count > probe_arc->cs_count)
01669 {
01670 cycle_count = probe_arc->cs_count;
01671 cycle_arc = probe_arc;
01672 }
01673
01674 count += cycle_count;
01675 cycle_arc->cycle = 1;
01676
01677
01678 arc->cs_count -= cycle_count;
01679 for (dst = head; (probe_arc = dst->u.cycle.arc);
01680 dst = probe_arc->src)
01681 probe_arc->cs_count -= cycle_count;
01682
01683
01684 while (head != cycle_arc->src)
01685 {
01686 arc = head->u.cycle.arc;
01687 head->u.cycle.arc = NULL;
01688 head = arc->src;
01689 }
01690
01691 arc = arc->succ_next;
01692 continue;
01693 }
01694
01695
01696 dst->u.cycle.arc = arc;
01697 head = dst;
01698 goto next_vertex;
01699 }
01700
01701
01702 arc = head->u.cycle.arc;
01703 if (arc)
01704 {
01705
01706 head->u.cycle.arc = NULL;
01707 head = arc->src;
01708 arc = arc->succ_next;
01709 goto current_vertex;
01710 }
01711
01712 block->u.cycle.ident = ~0U;
01713 }
01714
01715 line->count = count;
01716 }
01717
01718 if (line->exists)
01719 {
01720 src->coverage.lines++;
01721 if (line->count)
01722 src->coverage.lines_executed++;
01723 }
01724 }
01725 }
01726
01727
01728
01729
01730 static int
01731 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
01732 {
01733
01734 if (arc->is_call_non_return)
01735 {
01736 if (arc->src->count)
01737 {
01738 fnotice (gcov_file, "call %2d returned %s\n", ix,
01739 format_gcov (arc->src->count - arc->count,
01740 arc->src->count, -flag_counts));
01741 }
01742 else
01743 fnotice (gcov_file, "call %2d never executed\n", ix);
01744 }
01745 else if (!arc->is_unconditional)
01746 {
01747 if (arc->src->count)
01748 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
01749 format_gcov (arc->count, arc->src->count, -flag_counts),
01750 arc->fall_through ? " (fallthrough)" : "");
01751 else
01752 fnotice (gcov_file, "branch %2d never executed\n", ix);
01753 }
01754 else if (flag_unconditional && !arc->dst->is_call_return)
01755 {
01756 if (arc->src->count)
01757 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
01758 format_gcov (arc->count, arc->src->count, -flag_counts));
01759 else
01760 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
01761 }
01762 else
01763 return 0;
01764 return 1;
01765
01766 }
01767
01768
01769
01770
01771
01772 static void
01773 output_lines (FILE *gcov_file, const source_t *src)
01774 {
01775 FILE *source_file;
01776 unsigned line_num;
01777 const line_t *line;
01778 char string[STRING_SIZE];
01779 char const *retval = "";
01780 function_t *fn = NULL;
01781
01782 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
01783 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
01784 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
01785 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
01786 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
01787 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
01788
01789 source_file = fopen (src->name, "r");
01790 if (!source_file)
01791 {
01792 fnotice (stderr, "%s:cannot open source file\n", src->name);
01793 retval = NULL;
01794 }
01795 else
01796 {
01797 struct stat status;
01798
01799 if (!fstat (fileno (source_file), &status)
01800 && status.st_mtime > bbg_file_time)
01801 {
01802 fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
01803 src->name, bbg_file_name);
01804 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
01805 "-", 0);
01806 }
01807 }
01808
01809 if (flag_branches)
01810 fn = src->functions;
01811
01812 for (line_num = 1, line = &src->lines[line_num];
01813 line_num < src->num_lines; line_num++, line++)
01814 {
01815 for (; fn && fn->line == line_num; fn = fn->line_next)
01816 {
01817 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
01818 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
01819
01820 for (; arc; arc = arc->pred_next)
01821 if (arc->fake)
01822 return_count -= arc->count;
01823
01824 fprintf (gcov_file, "function %s", fn->name);
01825 fprintf (gcov_file, " called %s",
01826 format_gcov (fn->blocks[0].count, 0, -1));
01827 fprintf (gcov_file, " returned %s",
01828 format_gcov (return_count, fn->blocks[0].count, 0));
01829 fprintf (gcov_file, " blocks executed %s",
01830 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
01831 fprintf (gcov_file, "\n");
01832 }
01833
01834
01835
01836
01837
01838
01839
01840 fprintf (gcov_file, "%9s:%5u:",
01841 !line->exists ? "-" : !line->count ? "#####"
01842 : format_gcov (line->count, 0, -1), line_num);
01843
01844 if (retval)
01845 {
01846
01847 do
01848 {
01849 retval = fgets (string, STRING_SIZE, source_file);
01850 if (!retval)
01851 break;
01852 fputs (retval, gcov_file);
01853 }
01854 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
01855 }
01856 if (!retval)
01857 fputs ("/*EOF*/\n", gcov_file);
01858
01859 if (flag_all_blocks)
01860 {
01861 block_t *block;
01862 arc_t *arc;
01863 int ix, jx;
01864
01865 for (ix = jx = 0, block = line->u.blocks; block;
01866 block = block->chain)
01867 {
01868 if (!block->is_call_return)
01869 fprintf (gcov_file, "%9s:%5u-block %2d\n",
01870 !line->exists ? "-" : !block->count ? "$$$$$"
01871 : format_gcov (block->count, 0, -1),
01872 line_num, ix++);
01873 if (flag_branches)
01874 for (arc = block->succ; arc; arc = arc->succ_next)
01875 jx += output_branch_count (gcov_file, jx, arc);
01876 }
01877 }
01878 else if (flag_branches)
01879 {
01880 int ix;
01881 arc_t *arc;
01882
01883 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
01884 ix += output_branch_count (gcov_file, ix, arc);
01885 }
01886 }
01887
01888
01889
01890 if (retval)
01891 {
01892 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
01893 {
01894 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
01895
01896 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
01897 {
01898 retval = fgets (string, STRING_SIZE, source_file);
01899 if (!retval)
01900 break;
01901 fputs (retval, gcov_file);
01902 }
01903 }
01904 }
01905
01906 if (source_file)
01907 fclose (source_file);
01908 }