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

Subversion Repositories openrisc_me

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

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

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

powered by: WebSVN 2.1.0

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