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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [coverage.c] - Blame information for rev 20

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

Line No. Rev Author Line
1 12 jlechner
/* Read and write coverage files, and associated functionality.
2
   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
3
   2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
4
   Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
5
   based on some ideas from Dain Samples of UC Berkeley.
6
   Further mangling by Bob Manson, Cygnus Support.
7
   Further mangled by Nathan Sidwell, CodeSourcery
8
 
9
This file is part of GCC.
10
 
11
GCC is free software; you can redistribute it and/or modify it under
12
the terms of the GNU General Public License as published by the Free
13
Software Foundation; either version 2, or (at your option) any later
14
version.
15
 
16
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17
WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19
for more details.
20
 
21
You should have received a copy of the GNU General Public License
22
along with GCC; see the file COPYING.  If not, write to the Free
23
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24
02110-1301, USA.  */
25
 
26
 
27
#define GCOV_LINKAGE
28
 
29
#include "config.h"
30
#include "system.h"
31
#include "coretypes.h"
32
#include "tm.h"
33
#include "rtl.h"
34
#include "tree.h"
35
#include "flags.h"
36
#include "output.h"
37
#include "regs.h"
38
#include "expr.h"
39
#include "function.h"
40
#include "toplev.h"
41
#include "ggc.h"
42
#include "coverage.h"
43
#include "langhooks.h"
44
#include "hashtab.h"
45
#include "tree-iterator.h"
46
#include "cgraph.h"
47
 
48
#include "gcov-io.c"
49
 
50
struct function_list
51
{
52
  struct function_list *next;    /* next function */
53
  unsigned ident;                /* function ident */
54
  unsigned checksum;             /* function checksum */
55
  unsigned n_ctrs[GCOV_COUNTERS];/* number of counters.  */
56
};
57
 
58
/* Counts information for a function.  */
59
typedef struct counts_entry
60
{
61
  /* We hash by  */
62
  unsigned ident;
63
  unsigned ctr;
64
 
65
  /* Store  */
66
  unsigned checksum;
67
  gcov_type *counts;
68
  struct gcov_ctr_summary summary;
69
 
70
  /* Workspace */
71
  struct counts_entry *chain;
72
 
73
} counts_entry_t;
74
 
75
static struct function_list *functions_head = 0;
76
static struct function_list **functions_tail = &functions_head;
77
static unsigned no_coverage = 0;
78
 
79
/* Cumulative counter information for whole program.  */
80
static unsigned prg_ctr_mask; /* Mask of counter types generated.  */
81
static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated.  */
82
 
83
/* Counter information for current function.  */
84
static unsigned fn_ctr_mask; /* Mask of counters used.  */
85
static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
86
static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
87
 
88
/* Name of the output file for coverage output file.  */
89
static char *bbg_file_name;
90
static unsigned bbg_file_opened;
91
static int bbg_function_announced;
92
 
93
/* Name of the count data file.  */
94
static char *da_file_name;
95
 
96
/* Hash table of count data.  */
97
static htab_t counts_hash = NULL;
98
 
99
/* Trees representing the counter table arrays.  */
100
static GTY(()) tree tree_ctr_tables[GCOV_COUNTERS];
101
 
102
/* The names of the counter tables.  Not used if we're
103
   generating counters at tree level.  */
104
static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
105
 
106
/* The names of merge functions for counters.  */
107
static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
108
static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
109
 
110
/* Forward declarations.  */
111
static hashval_t htab_counts_entry_hash (const void *);
112
static int htab_counts_entry_eq (const void *, const void *);
113
static void htab_counts_entry_del (void *);
114
static void read_counts_file (void);
115
static unsigned compute_checksum (void);
116
static unsigned coverage_checksum_string (unsigned, const char *);
117
static tree build_fn_info_type (unsigned);
118
static tree build_fn_info_value (const struct function_list *, tree);
119
static tree build_ctr_info_type (void);
120
static tree build_ctr_info_value (unsigned, tree);
121
static tree build_gcov_info (void);
122
static void create_coverage (void);
123
 
124
/* Return the type node for gcov_type.  */
125
 
126
tree
127
get_gcov_type (void)
128
{
129
  return lang_hooks.types.type_for_size (GCOV_TYPE_SIZE, false);
130
}
131
 
132
/* Return the type node for gcov_unsigned_t.  */
133
 
134
static tree
135
get_gcov_unsigned_t (void)
136
{
137
  return lang_hooks.types.type_for_size (32, true);
138
}
139
 
140
static hashval_t
141
htab_counts_entry_hash (const void *of)
142
{
143
  const counts_entry_t *entry = of;
144
 
145
  return entry->ident * GCOV_COUNTERS + entry->ctr;
146
}
147
 
148
static int
149
htab_counts_entry_eq (const void *of1, const void *of2)
150
{
151
  const counts_entry_t *entry1 = of1;
152
  const counts_entry_t *entry2 = of2;
153
 
154
  return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
155
}
156
 
157
static void
158
htab_counts_entry_del (void *of)
159
{
160
  counts_entry_t *entry = of;
161
 
162
  free (entry->counts);
163
  free (entry);
164
}
165
 
166
/* Read in the counts file, if available.  */
167
 
168
static void
169
read_counts_file (void)
170
{
171
  gcov_unsigned_t fn_ident = 0;
172
  gcov_unsigned_t checksum = -1;
173
  counts_entry_t *summaried = NULL;
174
  unsigned seen_summary = 0;
175
  gcov_unsigned_t tag;
176
  int is_error = 0;
177
 
178
  if (!gcov_open (da_file_name, 1))
179
    return;
180
 
181
  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
182
    {
183
      warning (0, "%qs is not a gcov data file", da_file_name);
184
      gcov_close ();
185
      return;
186
    }
187
  else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
188
    {
189
      char v[4], e[4];
190
 
191
      GCOV_UNSIGNED2STRING (v, tag);
192
      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
193
 
194
      warning (0, "%qs is version %q.*s, expected version %q.*s",
195
               da_file_name, 4, v, 4, e);
196
      gcov_close ();
197
      return;
198
    }
199
 
200
  /* Read and discard the stamp.  */
201
  gcov_read_unsigned ();
202
 
203
  counts_hash = htab_create (10,
204
                             htab_counts_entry_hash, htab_counts_entry_eq,
205
                             htab_counts_entry_del);
206
  while ((tag = gcov_read_unsigned ()))
207
    {
208
      gcov_unsigned_t length;
209
      gcov_position_t offset;
210
 
211
      length = gcov_read_unsigned ();
212
      offset = gcov_position ();
213
      if (tag == GCOV_TAG_FUNCTION)
214
        {
215
          fn_ident = gcov_read_unsigned ();
216
          checksum = gcov_read_unsigned ();
217
          if (seen_summary)
218
            {
219
              /* We have already seen a summary, this means that this
220
                 new function begins a new set of program runs. We
221
                 must unlink the summaried chain.  */
222
              counts_entry_t *entry, *chain;
223
 
224
              for (entry = summaried; entry; entry = chain)
225
                {
226
                  chain = entry->chain;
227
                  entry->chain = NULL;
228
                }
229
              summaried = NULL;
230
              seen_summary = 0;
231
            }
232
        }
233
      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
234
        {
235
          counts_entry_t *entry;
236
          struct gcov_summary summary;
237
 
238
          gcov_read_summary (&summary);
239
          seen_summary = 1;
240
          for (entry = summaried; entry; entry = entry->chain)
241
            {
242
              struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
243
 
244
              entry->summary.runs += csum->runs;
245
              entry->summary.sum_all += csum->sum_all;
246
              if (entry->summary.run_max < csum->run_max)
247
                entry->summary.run_max = csum->run_max;
248
              entry->summary.sum_max += csum->sum_max;
249
            }
250
        }
251
      else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
252
        {
253
          counts_entry_t **slot, *entry, elt;
254
          unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
255
          unsigned ix;
256
 
257
          elt.ident = fn_ident;
258
          elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
259
 
260
          slot = (counts_entry_t **) htab_find_slot
261
            (counts_hash, &elt, INSERT);
262
          entry = *slot;
263
          if (!entry)
264
            {
265
              *slot = entry = xcalloc (1, sizeof (counts_entry_t));
266
              entry->ident = elt.ident;
267
              entry->ctr = elt.ctr;
268
              entry->checksum = checksum;
269
              entry->summary.num = n_counts;
270
              entry->counts = xcalloc (n_counts, sizeof (gcov_type));
271
            }
272
          else if (entry->checksum != checksum)
273
            {
274
              error ("coverage mismatch for function %u while reading execution counters",
275
                     fn_ident);
276
              error ("checksum is %x instead of %x", entry->checksum, checksum);
277
              htab_delete (counts_hash);
278
              break;
279
            }
280
          else if (entry->summary.num != n_counts)
281
            {
282
              error ("coverage mismatch for function %u while reading execution counters",
283
                     fn_ident);
284
              error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
285
              htab_delete (counts_hash);
286
              break;
287
            }
288
          else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
289
            {
290
              error ("cannot merge separate %s counters for function %u",
291
                     ctr_names[elt.ctr], fn_ident);
292
              goto skip_merge;
293
            }
294
 
295
          if (elt.ctr < GCOV_COUNTERS_SUMMABLE
296
              /* This should always be true for a just allocated entry,
297
                 and always false for an existing one. Check this way, in
298
                 case the gcov file is corrupt.  */
299
              && (!entry->chain || summaried != entry))
300
            {
301
              entry->chain = summaried;
302
              summaried = entry;
303
            }
304
          for (ix = 0; ix != n_counts; ix++)
305
            entry->counts[ix] += gcov_read_counter ();
306
        skip_merge:;
307
        }
308
      gcov_sync (offset, length);
309
      if ((is_error = gcov_is_error ()))
310
        {
311
          error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
312
                 da_file_name);
313
          htab_delete (counts_hash);
314
          break;
315
        }
316
    }
317
 
318
  gcov_close ();
319
}
320
 
321
/* Returns the counters for a particular tag.  */
322
 
323
gcov_type *
324
get_coverage_counts (unsigned counter, unsigned expected,
325
                     const struct gcov_ctr_summary **summary)
326
{
327
  counts_entry_t *entry, elt;
328
  gcov_unsigned_t checksum = -1;
329
 
330
  /* No hash table, no counts.  */
331
  if (!counts_hash)
332
    {
333
      static int warned = 0;
334
 
335
      if (!warned++)
336
        inform ((flag_guess_branch_prob
337
                 ? "file %s not found, execution counts estimated"
338
                 : "file %s not found, execution counts assumed to be zero"),
339
                da_file_name);
340
      return NULL;
341
    }
342
 
343
  elt.ident = current_function_funcdef_no + 1;
344
  elt.ctr = counter;
345
  entry = htab_find (counts_hash, &elt);
346
  if (!entry)
347
    {
348
      warning (0, "no coverage for function %qs found", IDENTIFIER_POINTER
349
               (DECL_ASSEMBLER_NAME (current_function_decl)));
350
      return 0;
351
    }
352
 
353
  checksum = compute_checksum ();
354
  if (entry->checksum != checksum)
355
    {
356
      error ("coverage mismatch for function %qs while reading counter %qs",
357
             IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
358
             ctr_names[counter]);
359
      error ("checksum is %x instead of %x", entry->checksum, checksum);
360
      return 0;
361
    }
362
  else if (entry->summary.num != expected)
363
    {
364
      error ("coverage mismatch for function %qs while reading counter %qs",
365
             IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
366
             ctr_names[counter]);
367
      error ("number of counters is %d instead of %d", entry->summary.num, expected);
368
      return 0;
369
    }
370
 
371
  if (summary)
372
    *summary = &entry->summary;
373
 
374
  return entry->counts;
375
}
376
 
377
/* Allocate NUM counters of type COUNTER. Returns nonzero if the
378
   allocation succeeded.  */
379
 
380
int
381
coverage_counter_alloc (unsigned counter, unsigned num)
382
{
383
  if (no_coverage)
384
    return 0;
385
 
386
  if (!num)
387
    return 1;
388
 
389
  if (!tree_ctr_tables[counter])
390
    {
391
      /* Generate and save a copy of this so it can be shared.  */
392
      /* We don't know the size yet; make it big enough that nobody
393
         will make any clever transformation on it.  */
394
      char buf[20];
395
      tree gcov_type_node = get_gcov_type ();
396
      tree domain_tree
397
        = build_index_type (build_int_cst (NULL_TREE, 1000)); /* replaced later */
398
      tree gcov_type_array_type
399
        = build_array_type (gcov_type_node, domain_tree);
400
      tree_ctr_tables[counter]
401
        = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type);
402
      TREE_STATIC (tree_ctr_tables[counter]) = 1;
403
      ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
404
      DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf);
405
      DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (gcov_type_node);
406
    }
407
  fn_b_ctrs[counter] = fn_n_ctrs[counter];
408
  fn_n_ctrs[counter] += num;
409
  fn_ctr_mask |= 1 << counter;
410
  return 1;
411
}
412
 
413
/* Generate a tree to access COUNTER NO.  */
414
 
415
tree
416
tree_coverage_counter_ref (unsigned counter, unsigned no)
417
{
418
  tree gcov_type_node = get_gcov_type ();
419
  tree domain_type = TYPE_DOMAIN (TREE_TYPE (tree_ctr_tables[counter]));
420
 
421
  gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
422
  no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
423
 
424
  /* "no" here is an array index, scaled to bytes later.  */
425
  return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter],
426
                 fold_convert (domain_type,
427
                               build_int_cst (NULL_TREE, no)),
428
                 TYPE_MIN_VALUE (domain_type),
429
                 size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (gcov_type_node),
430
                             size_int (TYPE_ALIGN_UNIT (gcov_type_node))));
431
}
432
 
433
/* Generate a checksum for a string.  CHKSUM is the current
434
   checksum.  */
435
 
436
static unsigned
437
coverage_checksum_string (unsigned chksum, const char *string)
438
{
439
  int i;
440
  char *dup = NULL;
441
 
442
  /* Look for everything that looks if it were produced by
443
     get_file_function_name_long and zero out the second part
444
     that may result from flag_random_seed.  This is not critical
445
     as the checksums are used only for sanity checking.  */
446
  for (i = 0; string[i]; i++)
447
    {
448
      int offset = 0;
449
      if (!strncmp (string + i, "_GLOBAL__N_", 11))
450
      offset = 11;
451
      if (!strncmp (string + i, "_GLOBAL__", 9))
452
      offset = 9;
453
 
454
      /* C++ namespaces do have scheme:
455
         _GLOBAL__N_<filename>_<wrongmagicnumber>_<magicnumber>functionname
456
       since filename might contain extra underscores there seems
457
       to be no better chance then walk all possible offsets looking
458
       for magicnuber.  */
459
      if (offset)
460
        for (;string[offset]; offset++)
461
        for (i = i + offset; string[i]; i++)
462
          if (string[i]=='_')
463
            {
464
              int y;
465
 
466
              for (y = 1; y < 9; y++)
467
                if (!(string[i + y] >= '0' && string[i + y] <= '9')
468
                    && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
469
                  break;
470
              if (y != 9 || string[i + 9] != '_')
471
                continue;
472
              for (y = 10; y < 18; y++)
473
                if (!(string[i + y] >= '0' && string[i + y] <= '9')
474
                    && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
475
                  break;
476
              if (y != 18)
477
                continue;
478
              if (!dup)
479
                string = dup = xstrdup (string);
480
              for (y = 10; y < 18; y++)
481
                dup[i + y] = '0';
482
            }
483
        break;
484
    }
485
 
486
  chksum = crc32_string (chksum, string);
487
  if (dup)
488
    free (dup);
489
 
490
  return chksum;
491
}
492
 
493
/* Compute checksum for the current function.  We generate a CRC32.  */
494
 
495
static unsigned
496
compute_checksum (void)
497
{
498
  expanded_location xloc
499
    = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
500
  unsigned chksum = xloc.line;
501
 
502
  chksum = coverage_checksum_string (chksum, xloc.file);
503
  chksum = coverage_checksum_string
504
    (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
505
 
506
  return chksum;
507
}
508
 
509
/* Begin output to the graph file for the current function.
510
   Opens the output file, if not already done. Writes the
511
   function header, if not already done. Returns nonzero if data
512
   should be output.  */
513
 
514
int
515
coverage_begin_output (void)
516
{
517
  if (no_coverage)
518
    return 0;
519
 
520
  if (!bbg_function_announced)
521
    {
522
      expanded_location xloc
523
        = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
524
      unsigned long offset;
525
 
526
      if (!bbg_file_opened)
527
        {
528
          if (!gcov_open (bbg_file_name, -1))
529
            error ("cannot open %s", bbg_file_name);
530
          else
531
            {
532
              gcov_write_unsigned (GCOV_NOTE_MAGIC);
533
              gcov_write_unsigned (GCOV_VERSION);
534
              gcov_write_unsigned (local_tick);
535
            }
536
          bbg_file_opened = 1;
537
        }
538
 
539
      /* Announce function */
540
      offset = gcov_write_tag (GCOV_TAG_FUNCTION);
541
      gcov_write_unsigned (current_function_funcdef_no + 1);
542
      gcov_write_unsigned (compute_checksum ());
543
      gcov_write_string (IDENTIFIER_POINTER
544
                         (DECL_ASSEMBLER_NAME (current_function_decl)));
545
      gcov_write_string (xloc.file);
546
      gcov_write_unsigned (xloc.line);
547
      gcov_write_length (offset);
548
 
549
      bbg_function_announced = 1;
550
    }
551
  return !gcov_is_error ();
552
}
553
 
554
/* Finish coverage data for the current function. Verify no output
555
   error has occurred.  Save function coverage counts.  */
556
 
557
void
558
coverage_end_function (void)
559
{
560
  unsigned i;
561
 
562
  if (bbg_file_opened > 1 && gcov_is_error ())
563
    {
564
      warning (0, "error writing %qs", bbg_file_name);
565
      bbg_file_opened = -1;
566
    }
567
 
568
  if (fn_ctr_mask)
569
    {
570
      struct function_list *item;
571
 
572
      item = xmalloc (sizeof (struct function_list));
573
 
574
      *functions_tail = item;
575
      functions_tail = &item->next;
576
 
577
      item->next = 0;
578
      item->ident = current_function_funcdef_no + 1;
579
      item->checksum = compute_checksum ();
580
      for (i = 0; i != GCOV_COUNTERS; i++)
581
        {
582
          item->n_ctrs[i] = fn_n_ctrs[i];
583
          prg_n_ctrs[i] += fn_n_ctrs[i];
584
          fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
585
        }
586
      prg_ctr_mask |= fn_ctr_mask;
587
      fn_ctr_mask = 0;
588
    }
589
  bbg_function_announced = 0;
590
}
591
 
592
/* Creates the gcov_fn_info RECORD_TYPE.  */
593
 
594
static tree
595
build_fn_info_type (unsigned int counters)
596
{
597
  tree type = lang_hooks.types.make_type (RECORD_TYPE);
598
  tree field, fields;
599
  tree array_type;
600
 
601
  /* ident */
602
  fields = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
603
 
604
  /* checksum */
605
  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
606
  TREE_CHAIN (field) = fields;
607
  fields = field;
608
 
609
  array_type = build_int_cst (NULL_TREE, counters - 1);
610
  array_type = build_index_type (array_type);
611
  array_type = build_array_type (unsigned_type_node, array_type);
612
 
613
  /* counters */
614
  field = build_decl (FIELD_DECL, NULL_TREE, array_type);
615
  TREE_CHAIN (field) = fields;
616
  fields = field;
617
 
618
  finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
619
 
620
  return type;
621
}
622
 
623
/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
624
   the function being processed and TYPE is the gcov_fn_info
625
   RECORD_TYPE.  */
626
 
627
static tree
628
build_fn_info_value (const struct function_list *function, tree type)
629
{
630
  tree value = NULL_TREE;
631
  tree fields = TYPE_FIELDS (type);
632
  unsigned ix;
633
  tree array_value = NULL_TREE;
634
 
635
  /* ident */
636
  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
637
                                             function->ident), value);
638
  fields = TREE_CHAIN (fields);
639
 
640
  /* checksum */
641
  value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (),
642
                                             function->checksum), value);
643
  fields = TREE_CHAIN (fields);
644
 
645
  /* counters */
646
  for (ix = 0; ix != GCOV_COUNTERS; ix++)
647
    if (prg_ctr_mask & (1 << ix))
648
      {
649
        tree counters = build_int_cstu (unsigned_type_node,
650
                                        function->n_ctrs[ix]);
651
 
652
        array_value = tree_cons (NULL_TREE, counters, array_value);
653
      }
654
 
655
  /* FIXME: use build_constructor directly.  */
656
  array_value = build_constructor_from_list (TREE_TYPE (fields),
657
                                             nreverse (array_value));
658
  value = tree_cons (fields, array_value, value);
659
 
660
  /* FIXME: use build_constructor directly.  */
661
  value = build_constructor_from_list (type, nreverse (value));
662
 
663
  return value;
664
}
665
 
666
/* Creates the gcov_ctr_info RECORD_TYPE.  */
667
 
668
static tree
669
build_ctr_info_type (void)
670
{
671
  tree type = lang_hooks.types.make_type (RECORD_TYPE);
672
  tree field, fields = NULL_TREE;
673
  tree gcov_ptr_type = build_pointer_type (get_gcov_type ());
674
  tree gcov_merge_fn_type;
675
 
676
  /* counters */
677
  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
678
  TREE_CHAIN (field) = fields;
679
  fields = field;
680
 
681
  /* values */
682
  field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
683
  TREE_CHAIN (field) = fields;
684
  fields = field;
685
 
686
  /* merge */
687
  gcov_merge_fn_type =
688
    build_function_type_list (void_type_node,
689
                              gcov_ptr_type, unsigned_type_node,
690
                              NULL_TREE);
691
  field = build_decl (FIELD_DECL, NULL_TREE,
692
                      build_pointer_type (gcov_merge_fn_type));
693
  TREE_CHAIN (field) = fields;
694
  fields = field;
695
 
696
  finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
697
 
698
  return type;
699
}
700
 
701
/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
702
   the counter being processed and TYPE is the gcov_ctr_info
703
   RECORD_TYPE.  */
704
 
705
static tree
706
build_ctr_info_value (unsigned int counter, tree type)
707
{
708
  tree value = NULL_TREE;
709
  tree fields = TYPE_FIELDS (type);
710
  tree fn;
711
 
712
  /* counters */
713
  value = tree_cons (fields,
714
                     build_int_cstu (get_gcov_unsigned_t (),
715
                                     prg_n_ctrs[counter]),
716
                     value);
717
  fields = TREE_CHAIN (fields);
718
 
719
  if (prg_n_ctrs[counter])
720
    {
721
      tree array_type;
722
 
723
      array_type = build_int_cstu (unsigned_type_node,
724
                                   prg_n_ctrs[counter] - 1);
725
      array_type = build_index_type (array_type);
726
      array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
727
                                     array_type);
728
 
729
      TREE_TYPE (tree_ctr_tables[counter]) = array_type;
730
      DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type);
731
      DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type);
732
      assemble_variable (tree_ctr_tables[counter], 0, 0, 0);
733
 
734
      value = tree_cons (fields,
735
                         build1 (ADDR_EXPR, TREE_TYPE (fields),
736
                                            tree_ctr_tables[counter]),
737
                         value);
738
    }
739
  else
740
    value = tree_cons (fields, null_pointer_node, value);
741
  fields = TREE_CHAIN (fields);
742
 
743
  fn = build_decl (FUNCTION_DECL,
744
                   get_identifier (ctr_merge_functions[counter]),
745
                   TREE_TYPE (TREE_TYPE (fields)));
746
  DECL_EXTERNAL (fn) = 1;
747
  TREE_PUBLIC (fn) = 1;
748
  DECL_ARTIFICIAL (fn) = 1;
749
  TREE_NOTHROW (fn) = 1;
750
  value = tree_cons (fields,
751
                     build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
752
                     value);
753
 
754
  /* FIXME: use build_constructor directly.  */
755
  value = build_constructor_from_list (type, nreverse (value));
756
 
757
  return value;
758
}
759
 
760
/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
761
   CONSTRUCTOR.  */
762
 
763
static tree
764
build_gcov_info (void)
765
{
766
  unsigned n_ctr_types, ix;
767
  tree type, const_type;
768
  tree fn_info_type, fn_info_value = NULL_TREE;
769
  tree fn_info_ptr_type;
770
  tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
771
  tree field, fields = NULL_TREE;
772
  tree value = NULL_TREE;
773
  tree filename_string;
774
  char *filename;
775
  int filename_len;
776
  unsigned n_fns;
777
  const struct function_list *fn;
778
  tree string_type;
779
 
780
  /* Count the number of active counters.  */
781
  for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
782
    if (prg_ctr_mask & (1 << ix))
783
      n_ctr_types++;
784
 
785
  type = lang_hooks.types.make_type (RECORD_TYPE);
786
  const_type = build_qualified_type (type, TYPE_QUAL_CONST);
787
 
788
  /* Version ident */
789
  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
790
  TREE_CHAIN (field) = fields;
791
  fields = field;
792
  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), GCOV_VERSION),
793
                     value);
794
 
795
  /* next -- NULL */
796
  field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
797
  TREE_CHAIN (field) = fields;
798
  fields = field;
799
  value = tree_cons (field, null_pointer_node, value);
800
 
801
  /* stamp */
802
  field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
803
  TREE_CHAIN (field) = fields;
804
  fields = field;
805
  value = tree_cons (field, build_int_cstu (TREE_TYPE (field), local_tick),
806
                     value);
807
 
808
  /* Filename */
809
  string_type = build_pointer_type (build_qualified_type (char_type_node,
810
                                                    TYPE_QUAL_CONST));
811
  field = build_decl (FIELD_DECL, NULL_TREE, string_type);
812
  TREE_CHAIN (field) = fields;
813
  fields = field;
814
  filename = getpwd ();
815
  filename = (filename && da_file_name[0] != '/'
816
              ? concat (filename, "/", da_file_name, NULL)
817
              : da_file_name);
818
  filename_len = strlen (filename);
819
  filename_string = build_string (filename_len + 1, filename);
820
  if (filename != da_file_name)
821
    free (filename);
822
  TREE_TYPE (filename_string) = build_array_type
823
    (char_type_node, build_index_type
824
     (build_int_cst (NULL_TREE, filename_len)));
825
  value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
826
                     value);
827
 
828
  /* Build the fn_info type and initializer.  */
829
  fn_info_type = build_fn_info_type (n_ctr_types);
830
  fn_info_ptr_type = build_pointer_type (build_qualified_type
831
                                         (fn_info_type, TYPE_QUAL_CONST));
832
  for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
833
    fn_info_value = tree_cons (NULL_TREE,
834
                               build_fn_info_value (fn, fn_info_type),
835
                               fn_info_value);
836
  if (n_fns)
837
    {
838
      tree array_type;
839
 
840
      array_type = build_index_type (build_int_cst (NULL_TREE, n_fns - 1));
841
      array_type = build_array_type (fn_info_type, array_type);
842
 
843
      /* FIXME: use build_constructor directly.  */
844
      fn_info_value = build_constructor_from_list (array_type,
845
                                                   nreverse (fn_info_value));
846
      fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
847
    }
848
  else
849
    fn_info_value = null_pointer_node;
850
 
851
  /* number of functions */
852
  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
853
  TREE_CHAIN (field) = fields;
854
  fields = field;
855
  value = tree_cons (field,
856
                     build_int_cstu (unsigned_type_node, n_fns),
857
                     value);
858
 
859
  /* fn_info table */
860
  field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
861
  TREE_CHAIN (field) = fields;
862
  fields = field;
863
  value = tree_cons (field, fn_info_value, value);
864
 
865
  /* counter_mask */
866
  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
867
  TREE_CHAIN (field) = fields;
868
  fields = field;
869
  value = tree_cons (field,
870
                     build_int_cstu (unsigned_type_node, prg_ctr_mask),
871
                     value);
872
 
873
  /* counters */
874
  ctr_info_type = build_ctr_info_type ();
875
  ctr_info_ary_type = build_index_type (build_int_cst (NULL_TREE,
876
                                                       n_ctr_types));
877
  ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
878
  for (ix = 0; ix != GCOV_COUNTERS; ix++)
879
    if (prg_ctr_mask & (1 << ix))
880
      ctr_info_value = tree_cons (NULL_TREE,
881
                                  build_ctr_info_value (ix, ctr_info_type),
882
                                  ctr_info_value);
883
  /* FIXME: use build_constructor directly.  */
884
  ctr_info_value = build_constructor_from_list (ctr_info_ary_type,
885
                                                nreverse (ctr_info_value));
886
 
887
  field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
888
  TREE_CHAIN (field) = fields;
889
  fields = field;
890
  value = tree_cons (field, ctr_info_value, value);
891
 
892
  finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
893
 
894
  /* FIXME: use build_constructor directly.  */
895
  value = build_constructor_from_list (type, nreverse (value));
896
 
897
  return value;
898
}
899
 
900
/* Write out the structure which libgcov uses to locate all the
901
   counters.  The structures used here must match those defined in
902
   gcov-io.h.  Write out the constructor to call __gcov_init.  */
903
 
904
static void
905
create_coverage (void)
906
{
907
  tree gcov_info, gcov_init, body, t;
908
  char name_buf[32];
909
 
910
  no_coverage = 1; /* Disable any further coverage.  */
911
 
912
  if (!prg_ctr_mask)
913
    return;
914
 
915
  t = build_gcov_info ();
916
 
917
  gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t));
918
  TREE_STATIC (gcov_info) = 1;
919
  ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
920
  DECL_NAME (gcov_info) = get_identifier (name_buf);
921
  DECL_INITIAL (gcov_info) = t;
922
 
923
  /* Build structure.  */
924
  assemble_variable (gcov_info, 0, 0, 0);
925
 
926
  /* Build a decl for __gcov_init.  */
927
  t = build_pointer_type (TREE_TYPE (gcov_info));
928
  t = build_function_type_list (void_type_node, t, NULL);
929
  t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t);
930
  TREE_PUBLIC (t) = 1;
931
  DECL_EXTERNAL (t) = 1;
932
  gcov_init = t;
933
 
934
  /* Generate a call to __gcov_init(&gcov_info).  */
935
  body = NULL;
936
  t = build_fold_addr_expr (gcov_info);
937
  t = tree_cons (NULL, t, NULL);
938
  t = build_function_call_expr (gcov_init, t);
939
  append_to_statement_list (t, &body);
940
 
941
  /* Generate a constructor to run it.  */
942
  cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
943
}
944
 
945
/* Perform file-level initialization. Read in data file, generate name
946
   of graph file.  */
947
 
948
void
949
coverage_init (const char *filename)
950
{
951
  int len = strlen (filename);
952
 
953
  /* Name of da file.  */
954
  da_file_name = xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
955
  strcpy (da_file_name, filename);
956
  strcat (da_file_name, GCOV_DATA_SUFFIX);
957
 
958
  /* Name of bbg file.  */
959
  bbg_file_name = xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1);
960
  strcpy (bbg_file_name, filename);
961
  strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
962
 
963
  read_counts_file ();
964
}
965
 
966
/* Performs file-level cleanup.  Close graph file, generate coverage
967
   variables and constructor.  */
968
 
969
void
970
coverage_finish (void)
971
{
972
  create_coverage ();
973
  if (bbg_file_opened)
974
    {
975
      int error = gcov_close ();
976
 
977
      if (error)
978
        unlink (bbg_file_name);
979
      if (!local_tick)
980
        /* Only remove the da file, if we cannot stamp it. If we can
981
           stamp it, libgcov will DTRT.  */
982
        unlink (da_file_name);
983
    }
984
}
985
 
986
#include "gt-coverage.h"

powered by: WebSVN 2.1.0

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