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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [gcov.c] - Blame information for rev 280

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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