OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [gcov.c] - Blame information for rev 749

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.