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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [gcov.c] - Blame information for rev 12

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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