]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/coverage.c
gcc_release (announce_snapshot): Use changedir instead of plain cd.
[thirdparty/gcc.git] / gcc / coverage.c
1 /* 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 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, 59 Temple Place - Suite 330, Boston, MA
24 02111-1307, 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 "target.h"
43 #include "coverage.h"
44 #include "libfuncs.h"
45 #include "langhooks.h"
46 #include "hashtab.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 /* The names of the counter tables. */
100 static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
101
102 /* The names of merge functions for counters. */
103 static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
104 static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
105
106 /* Forward declarations. */
107 static hashval_t htab_counts_entry_hash (const void *);
108 static int htab_counts_entry_eq (const void *, const void *);
109 static void htab_counts_entry_del (void *);
110 static void read_counts_file (void);
111 static unsigned compute_checksum (void);
112 static unsigned coverage_checksum_string (unsigned, const char *);
113 static tree build_fn_info_type (unsigned);
114 static tree build_fn_info_value (const struct function_list *, tree);
115 static tree build_ctr_info_type (void);
116 static tree build_ctr_info_value (unsigned, tree);
117 static tree build_gcov_info (void);
118 static void create_coverage (void);
119
120 \f
121 static hashval_t
122 htab_counts_entry_hash (const void *of)
123 {
124 const counts_entry_t *entry = of;
125
126 return entry->ident * GCOV_COUNTERS + entry->ctr;
127 }
128
129 static int
130 htab_counts_entry_eq (const void *of1, const void *of2)
131 {
132 const counts_entry_t *entry1 = of1;
133 const counts_entry_t *entry2 = of2;
134
135 return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
136 }
137
138 static void
139 htab_counts_entry_del (void *of)
140 {
141 counts_entry_t *entry = of;
142
143 free (entry->counts);
144 free (entry);
145 }
146
147 /* Read in the counts file, if available. */
148
149 static void
150 read_counts_file (void)
151 {
152 gcov_unsigned_t fn_ident = 0;
153 gcov_unsigned_t checksum = -1;
154 counts_entry_t *summaried = NULL;
155 unsigned seen_summary = 0;
156 gcov_unsigned_t tag;
157 int is_error = 0;
158
159 if (!gcov_open (da_file_name, 1))
160 return;
161
162 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
163 {
164 warning ("`%s' is not a gcov data file", da_file_name);
165 gcov_close ();
166 return;
167 }
168 else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
169 {
170 char v[4], e[4];
171
172 GCOV_UNSIGNED2STRING (v, tag);
173 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
174
175 warning ("`%s' is version `%.4s', expected version `%.4s'",
176 da_file_name, v, e);
177 gcov_close ();
178 return;
179 }
180
181 /* Read and discard the stamp. */
182 gcov_read_unsigned ();
183
184 counts_hash = htab_create (10,
185 htab_counts_entry_hash, htab_counts_entry_eq,
186 htab_counts_entry_del);
187 while ((tag = gcov_read_unsigned ()))
188 {
189 gcov_unsigned_t length;
190 gcov_position_t offset;
191
192 length = gcov_read_unsigned ();
193 offset = gcov_position ();
194 if (tag == GCOV_TAG_FUNCTION)
195 {
196 fn_ident = gcov_read_unsigned ();
197 checksum = gcov_read_unsigned ();
198 if (seen_summary)
199 {
200 /* We have already seen a summary, this means that this
201 new function begins a new set of program runs. We
202 must unlink the summaried chain. */
203 counts_entry_t *entry, *chain;
204
205 for (entry = summaried; entry; entry = chain)
206 {
207 chain = entry->chain;
208 entry->chain = NULL;
209 }
210 summaried = NULL;
211 seen_summary = 0;
212 }
213 }
214 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
215 {
216 counts_entry_t *entry;
217 struct gcov_summary summary;
218
219 gcov_read_summary (&summary);
220 seen_summary = 1;
221 for (entry = summaried; entry; entry = entry->chain)
222 {
223 struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
224
225 entry->summary.runs += csum->runs;
226 entry->summary.sum_all += csum->sum_all;
227 if (entry->summary.run_max < csum->run_max)
228 entry->summary.run_max = csum->run_max;
229 entry->summary.sum_max += csum->sum_max;
230 }
231 }
232 else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
233 {
234 counts_entry_t **slot, *entry, elt;
235 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
236 unsigned ix;
237
238 elt.ident = fn_ident;
239 elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
240
241 slot = (counts_entry_t **) htab_find_slot
242 (counts_hash, &elt, INSERT);
243 entry = *slot;
244 if (!entry)
245 {
246 *slot = entry = xcalloc (1, sizeof (counts_entry_t));
247 entry->ident = elt.ident;
248 entry->ctr = elt.ctr;
249 entry->checksum = checksum;
250 entry->summary.num = n_counts;
251 entry->counts = xcalloc (n_counts, sizeof (gcov_type));
252 }
253 else if (entry->checksum != checksum)
254 {
255 error ("coverage mismatch for function %u while reading execution counters.",
256 fn_ident);
257 error ("checksum is %x instead of %x", entry->checksum, checksum);
258 htab_delete (counts_hash);
259 break;
260 }
261 else if (entry->summary.num != n_counts)
262 {
263 error ("coverage mismatch for function %u while reading execution counters.",
264 fn_ident);
265 error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
266 htab_delete (counts_hash);
267 break;
268 }
269 else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
270 {
271 error ("cannot merge separate %s counters for function %u",
272 ctr_names[elt.ctr], fn_ident);
273 goto skip_merge;
274 }
275
276 if (elt.ctr < GCOV_COUNTERS_SUMMABLE
277 /* This should always be true for a just allocated entry,
278 and always false for an existing one. Check this way, in
279 case the gcov file is corrupt. */
280 && (!entry->chain || summaried != entry))
281 {
282 entry->chain = summaried;
283 summaried = entry;
284 }
285 for (ix = 0; ix != n_counts; ix++)
286 entry->counts[ix] += gcov_read_counter ();
287 skip_merge:;
288 }
289 gcov_sync (offset, length);
290 if ((is_error = gcov_is_error ()))
291 break;
292 }
293
294 if (!gcov_is_eof ())
295 {
296 error (is_error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
297 da_file_name);
298 htab_delete (counts_hash);
299 }
300
301 gcov_close ();
302 }
303
304 /* Returns the counters for a particular tag. */
305
306 gcov_type *
307 get_coverage_counts (unsigned counter, unsigned expected,
308 const struct gcov_ctr_summary **summary)
309 {
310 counts_entry_t *entry, elt;
311 gcov_unsigned_t checksum = -1;
312
313 /* No hash table, no counts. */
314 if (!counts_hash)
315 {
316 static int warned = 0;
317
318 if (!warned++)
319 inform ((flag_guess_branch_prob
320 ? "file %s not found, execution counts estimated"
321 : "file %s not found, execution counts assumed to be zero"),
322 da_file_name);
323 return NULL;
324 }
325
326 elt.ident = current_function_funcdef_no + 1;
327 elt.ctr = counter;
328 entry = htab_find (counts_hash, &elt);
329 if (!entry)
330 {
331 warning ("no coverage for function '%s' found.", IDENTIFIER_POINTER
332 (DECL_ASSEMBLER_NAME (current_function_decl)));
333 return 0;
334 }
335
336 checksum = compute_checksum ();
337 if (entry->checksum != checksum)
338 {
339 error ("coverage mismatch for function '%s' while reading counter '%s'.",
340 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
341 ctr_names[counter]);
342 error ("checksum is %x instead of %x", entry->checksum, checksum);
343 return 0;
344 }
345 else if (entry->summary.num != expected)
346 {
347 error ("coverage mismatch for function '%s' while reading counter '%s'.",
348 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
349 ctr_names[counter]);
350 error ("number of counters is %d instead of %d", entry->summary.num, expected);
351 return 0;
352 }
353
354 if (summary)
355 *summary = &entry->summary;
356
357 return entry->counts;
358 }
359
360 /* Allocate NUM counters of type COUNTER. Returns nonzero if the
361 allocation succeeded. */
362
363 int
364 coverage_counter_alloc (unsigned counter, unsigned num)
365 {
366 if (no_coverage)
367 return 0;
368
369 if (!num)
370 return 1;
371
372 if (!ctr_labels[counter])
373 {
374 /* Generate and save a copy of this so it can be shared. */
375 char buf[20];
376
377 ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
378 ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
379 SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL;
380 }
381 fn_b_ctrs[counter] = fn_n_ctrs[counter];
382 fn_n_ctrs[counter] += num;
383 fn_ctr_mask |= 1 << counter;
384 return 1;
385 }
386
387 /* Generate a MEM rtl to access COUNTER NO. */
388
389 rtx
390 coverage_counter_ref (unsigned counter, unsigned no)
391 {
392 unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
393 enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
394 rtx ref;
395
396 if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
397 abort ();
398 no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
399 ref = plus_constant (ctr_labels[counter], gcov_size / BITS_PER_UNIT * no);
400 ref = gen_rtx_MEM (mode, ref);
401 set_mem_alias_set (ref, new_alias_set ());
402 MEM_NOTRAP_P (ref) = 1;
403
404 return ref;
405 }
406 \f
407 /* Generate a checksum for a string. CHKSUM is the current
408 checksum. */
409
410 static unsigned
411 coverage_checksum_string (unsigned chksum, const char *string)
412 {
413 int i;
414 char *dup = NULL;
415
416 /* Look for everything that looks if it were produced by
417 get_file_function_name_long and zero out the second part
418 that may result from flag_random_seed. This is not critical
419 as the checksums are used only for sanity checking. */
420 for (i = 0; string[i]; i++)
421 {
422 if (!strncmp (string + i, "_GLOBAL__", 9))
423 for (i = i + 9; string[i]; i++)
424 if (string[i]=='_')
425 {
426 int y;
427 unsigned seed;
428
429 for (y = 1; y < 9; y++)
430 if (!(string[i + y] >= '0' && string[i + y] <= '9')
431 && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
432 break;
433 if (y != 9 || string[i + 9] != '_')
434 continue;
435 for (y = 10; y < 18; y++)
436 if (!(string[i + y] >= '0' && string[i + y] <= '9')
437 && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
438 break;
439 if (y != 18)
440 continue;
441 if (!sscanf (string + i + 10, "%X", &seed))
442 abort ();
443 if (seed != crc32_string (0, flag_random_seed))
444 continue;
445 string = dup = xstrdup (string);
446 for (y = 10; y < 18; y++)
447 dup[i + y] = '0';
448 break;
449 }
450 break;
451 }
452
453 chksum = crc32_string (chksum, string);
454 if (dup)
455 free (dup);
456
457 return chksum;
458 }
459
460 /* Compute checksum for the current function. We generate a CRC32. */
461
462 static unsigned
463 compute_checksum (void)
464 {
465 unsigned chksum = DECL_SOURCE_LINE (current_function_decl);
466
467 chksum = coverage_checksum_string (chksum,
468 DECL_SOURCE_FILE (current_function_decl));
469 chksum = coverage_checksum_string
470 (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
471
472 return chksum;
473 }
474 \f
475 /* Begin output to the graph file for the current function.
476 Opens the output file, if not already done. Writes the
477 function header, if not already done. Returns nonzero if data
478 should be output. */
479
480 int
481 coverage_begin_output (void)
482 {
483 if (no_coverage)
484 return 0;
485
486 if (!bbg_function_announced)
487 {
488 const char *file = DECL_SOURCE_FILE (current_function_decl);
489 unsigned line = DECL_SOURCE_LINE (current_function_decl);
490 unsigned long offset;
491
492 if (!bbg_file_opened)
493 {
494 if (!gcov_open (bbg_file_name, -1))
495 error ("cannot open %s", bbg_file_name);
496 else
497 {
498 gcov_write_unsigned (GCOV_NOTE_MAGIC);
499 gcov_write_unsigned (GCOV_VERSION);
500 gcov_write_unsigned (local_tick);
501 }
502 bbg_file_opened = 1;
503 }
504
505 /* Announce function */
506 offset = gcov_write_tag (GCOV_TAG_FUNCTION);
507 gcov_write_unsigned (current_function_funcdef_no + 1);
508 gcov_write_unsigned (compute_checksum ());
509 gcov_write_string (IDENTIFIER_POINTER
510 (DECL_ASSEMBLER_NAME (current_function_decl)));
511 gcov_write_string (file);
512 gcov_write_unsigned (line);
513 gcov_write_length (offset);
514
515 bbg_function_announced = 1;
516 }
517 return !gcov_is_error ();
518 }
519
520 /* Finish coverage data for the current function. Verify no output
521 error has occurred. Save function coverage counts. */
522
523 void
524 coverage_end_function (void)
525 {
526 unsigned i;
527
528 if (bbg_file_opened > 1 && gcov_is_error ())
529 {
530 warning ("error writing `%s'", bbg_file_name);
531 bbg_file_opened = -1;
532 }
533
534 if (fn_ctr_mask)
535 {
536 struct function_list *item;
537
538 item = xmalloc (sizeof (struct function_list));
539
540 *functions_tail = item;
541 functions_tail = &item->next;
542
543 item->next = 0;
544 item->ident = current_function_funcdef_no + 1;
545 item->checksum = compute_checksum ();
546 for (i = 0; i != GCOV_COUNTERS; i++)
547 {
548 item->n_ctrs[i] = fn_n_ctrs[i];
549 prg_n_ctrs[i] += fn_n_ctrs[i];
550 fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
551 }
552 prg_ctr_mask |= fn_ctr_mask;
553 fn_ctr_mask = 0;
554 }
555 bbg_function_announced = 0;
556 }
557
558 /* Creates the gcov_fn_info RECORD_TYPE. */
559
560 static tree
561 build_fn_info_type (unsigned int counters)
562 {
563 tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
564 tree field, fields;
565 tree array_type;
566
567 /* ident */
568 fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
569
570 /* checksum */
571 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
572 TREE_CHAIN (field) = fields;
573 fields = field;
574
575 array_type = build_index_type (build_int_2 (counters - 1, 0));
576 array_type = build_array_type (unsigned_type_node, array_type);
577
578 /* counters */
579 field = build_decl (FIELD_DECL, NULL_TREE, array_type);
580 TREE_CHAIN (field) = fields;
581 fields = field;
582
583 finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
584
585 return type;
586 }
587
588 /* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
589 the function being processed and TYPE is the gcov_fn_info
590 RECORD_TYPE. */
591
592 static tree
593 build_fn_info_value (const struct function_list *function, tree type)
594 {
595 tree value = NULL_TREE;
596 tree fields = TYPE_FIELDS (type);
597 unsigned ix;
598 tree array_value = NULL_TREE;
599
600 /* ident */
601 value = tree_cons (fields,
602 convert (unsigned_intSI_type_node,
603 build_int_2 (function->ident, 0)),
604 value);
605 fields = TREE_CHAIN (fields);
606
607 /* checksum */
608 value = tree_cons (fields,
609 convert (unsigned_intSI_type_node,
610 build_int_2 (function->checksum, 0)),
611 value);
612 fields = TREE_CHAIN (fields);
613
614 /* counters */
615 for (ix = 0; ix != GCOV_COUNTERS; ix++)
616 if (prg_ctr_mask & (1 << ix))
617 {
618 tree counters = convert (unsigned_type_node,
619 build_int_2 (function->n_ctrs[ix], 0));
620
621 array_value = tree_cons (NULL_TREE, counters, array_value);
622 }
623
624 array_value = build_constructor (TREE_TYPE (fields), nreverse (array_value));
625 value = tree_cons (fields, array_value, value);
626
627 value = build_constructor (type, nreverse (value));
628
629 return value;
630 }
631
632 /* Creates the gcov_ctr_info RECORD_TYPE. */
633
634 static tree
635 build_ctr_info_type (void)
636 {
637 tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
638 tree field, fields = NULL_TREE;
639 tree gcov_ptr_type = build_pointer_type (GCOV_TYPE_NODE);
640 tree gcov_merge_fn_type;
641
642 /* counters */
643 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
644 TREE_CHAIN (field) = fields;
645 fields = field;
646
647 /* values */
648 field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
649 TREE_CHAIN (field) = fields;
650 fields = field;
651
652 /* merge */
653 gcov_merge_fn_type =
654 build_function_type_list (void_type_node,
655 gcov_ptr_type, unsigned_type_node,
656 NULL_TREE);
657 field = build_decl (FIELD_DECL, NULL_TREE,
658 build_pointer_type (gcov_merge_fn_type));
659 TREE_CHAIN (field) = fields;
660 fields = field;
661
662 finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
663
664 return type;
665 }
666
667 /* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
668 the counter being processed and TYPE is the gcov_ctr_info
669 RECORD_TYPE. */
670
671 static tree
672 build_ctr_info_value (unsigned int counter, tree type)
673 {
674 tree value = NULL_TREE;
675 tree fields = TYPE_FIELDS (type);
676 tree fn;
677
678 /* counters */
679 value = tree_cons (fields,
680 convert (unsigned_intSI_type_node,
681 build_int_2 (prg_n_ctrs[counter], 0)),
682 value);
683 fields = TREE_CHAIN (fields);
684
685 if (prg_n_ctrs[counter])
686 {
687 tree array_type, array;
688
689 array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0));
690 array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
691 array_type);
692
693 array = build_decl (VAR_DECL, NULL_TREE, array_type);
694 TREE_STATIC (array) = 1;
695 DECL_NAME (array) = get_identifier (XSTR (ctr_labels[counter], 0));
696 assemble_variable (array, 0, 0, 0);
697
698 value = tree_cons (fields,
699 build1 (ADDR_EXPR, TREE_TYPE (fields), array),
700 value);
701 }
702 else
703 value = tree_cons (fields, null_pointer_node, value);
704 fields = TREE_CHAIN (fields);
705
706 fn = build_decl (FUNCTION_DECL,
707 get_identifier (ctr_merge_functions[counter]),
708 TREE_TYPE (TREE_TYPE (fields)));
709 DECL_EXTERNAL (fn) = 1;
710 TREE_PUBLIC (fn) = 1;
711 DECL_ARTIFICIAL (fn) = 1;
712 TREE_NOTHROW (fn) = 1;
713 value = tree_cons (fields,
714 build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
715 value);
716
717 value = build_constructor (type, nreverse (value));
718
719 return value;
720 }
721
722 /* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
723 CONSTRUCTOR. */
724
725 static tree
726 build_gcov_info (void)
727 {
728 unsigned n_ctr_types, ix;
729 tree type, const_type;
730 tree fn_info_type, fn_info_value = NULL_TREE;
731 tree fn_info_ptr_type;
732 tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
733 tree field, fields = NULL_TREE;
734 tree value = NULL_TREE;
735 tree filename_string;
736 char *filename;
737 int filename_len;
738 unsigned n_fns;
739 const struct function_list *fn;
740 tree string_type;
741
742 /* Count the number of active counters. */
743 for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
744 if (prg_ctr_mask & (1 << ix))
745 n_ctr_types++;
746
747 type = (*lang_hooks.types.make_type) (RECORD_TYPE);
748 const_type = build_qualified_type (type, TYPE_QUAL_CONST);
749
750 /* Version ident */
751 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
752 TREE_CHAIN (field) = fields;
753 fields = field;
754 value = tree_cons (field, convert (unsigned_intSI_type_node,
755 build_int_2 (GCOV_VERSION, 0)),
756 value);
757
758 /* next -- NULL */
759 field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
760 TREE_CHAIN (field) = fields;
761 fields = field;
762 value = tree_cons (field, null_pointer_node, value);
763
764 /* stamp */
765 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
766 TREE_CHAIN (field) = fields;
767 fields = field;
768 value = tree_cons (field, convert (unsigned_intSI_type_node,
769 build_int_2 (local_tick, 0)),
770 value);
771
772 /* Filename */
773 string_type = build_pointer_type (build_qualified_type (char_type_node,
774 TYPE_QUAL_CONST));
775 field = build_decl (FIELD_DECL, NULL_TREE, string_type);
776 TREE_CHAIN (field) = fields;
777 fields = field;
778 filename = getpwd ();
779 filename = (filename && da_file_name[0] != '/'
780 ? concat (filename, "/", da_file_name, NULL)
781 : da_file_name);
782 filename_len = strlen (filename);
783 filename_string = build_string (filename_len + 1, filename);
784 if (filename != da_file_name)
785 free (filename);
786 TREE_TYPE (filename_string) =
787 build_array_type (char_type_node,
788 build_index_type (build_int_2 (filename_len, 0)));
789 value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
790 value);
791
792 /* Build the fn_info type and initializer. */
793 fn_info_type = build_fn_info_type (n_ctr_types);
794 fn_info_ptr_type = build_pointer_type (build_qualified_type
795 (fn_info_type, TYPE_QUAL_CONST));
796 for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
797 fn_info_value = tree_cons (NULL_TREE,
798 build_fn_info_value (fn, fn_info_type),
799 fn_info_value);
800 if (n_fns)
801 {
802 tree array_type;
803
804 array_type = build_index_type (build_int_2 (n_fns - 1, 0));
805 array_type = build_array_type (fn_info_type, array_type);
806
807 fn_info_value = build_constructor (array_type, nreverse (fn_info_value));
808 fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
809 }
810 else
811 fn_info_value = null_pointer_node;
812
813 /* number of functions */
814 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
815 TREE_CHAIN (field) = fields;
816 fields = field;
817 value = tree_cons (field,
818 convert (unsigned_type_node, build_int_2 (n_fns, 0)),
819 value);
820
821 /* fn_info table */
822 field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
823 TREE_CHAIN (field) = fields;
824 fields = field;
825 value = tree_cons (field, fn_info_value, value);
826
827 /* counter_mask */
828 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
829 TREE_CHAIN (field) = fields;
830 fields = field;
831 value = tree_cons (field,
832 convert (unsigned_type_node,
833 build_int_2 (prg_ctr_mask, 0)),
834 value);
835
836 /* counters */
837 ctr_info_type = build_ctr_info_type ();
838 ctr_info_ary_type = build_index_type (build_int_2 (n_ctr_types, 0));
839 ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
840 for (ix = 0; ix != GCOV_COUNTERS; ix++)
841 if (prg_ctr_mask & (1 << ix))
842 ctr_info_value = tree_cons (NULL_TREE,
843 build_ctr_info_value (ix, ctr_info_type),
844 ctr_info_value);
845 ctr_info_value = build_constructor (ctr_info_ary_type,
846 nreverse (ctr_info_value));
847
848 field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
849 TREE_CHAIN (field) = fields;
850 fields = field;
851 value = tree_cons (field, ctr_info_value, value);
852
853 finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
854
855 value = build_constructor (type, nreverse (value));
856
857 return value;
858 }
859
860 /* Write out the structure which libgcov uses to locate all the
861 counters. The structures used here must match those defined in
862 gcov-io.h. Write out the constructor to call __gcov_init. */
863
864 static void
865 create_coverage (void)
866 {
867 tree gcov_info, gcov_info_value;
868 char name[20];
869 char *ctor_name;
870 tree ctor;
871 rtx gcov_info_address;
872
873 no_coverage = 1; /* Disable any further coverage. */
874
875 if (!prg_ctr_mask)
876 return;
877
878 gcov_info_value = build_gcov_info ();
879
880 gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (gcov_info_value));
881 DECL_INITIAL (gcov_info) = gcov_info_value;
882
883 TREE_STATIC (gcov_info) = 1;
884 ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
885 DECL_NAME (gcov_info) = get_identifier (name);
886
887 /* Build structure. */
888 assemble_variable (gcov_info, 0, 0, 0);
889
890 /* Build the constructor function to invoke __gcov_init. */
891 ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')),
892 "_GCOV", NULL);
893 ctor = build_decl (FUNCTION_DECL, get_identifier (ctor_name),
894 build_function_type (void_type_node, NULL_TREE));
895 free (ctor_name);
896 DECL_EXTERNAL (ctor) = 0;
897
898 /* It can be a static function as long as collect2 does not have
899 to scan the object file to find its ctor/dtor routine. */
900 TREE_PUBLIC (ctor) = ! targetm.have_ctors_dtors;
901 TREE_USED (ctor) = 1;
902 DECL_RESULT (ctor) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
903 DECL_UNINLINABLE (ctor) = 1;
904
905 ctor = (*lang_hooks.decls.pushdecl) (ctor);
906 rest_of_decl_compilation (ctor, 0, 1, 0);
907 announce_function (ctor);
908 current_function_decl = ctor;
909 make_decl_rtl (ctor, NULL);
910 init_function_start (ctor);
911 expand_function_start (ctor, 0);
912 /* Actually generate the code to call __gcov_init. */
913 gcov_info_address = force_reg (Pmode, XEXP (DECL_RTL (gcov_info), 0));
914 emit_library_call (gcov_init_libfunc, LCT_NORMAL, VOIDmode, 1,
915 gcov_info_address, Pmode);
916
917 expand_function_end ();
918 /* Create a dummy BLOCK. */
919 DECL_INITIAL (ctor) = make_node (BLOCK);
920 TREE_USED (DECL_INITIAL (ctor)) = 1;
921
922 rest_of_compilation (ctor);
923
924 if (! quiet_flag)
925 fflush (asm_out_file);
926 current_function_decl = NULL_TREE;
927
928 if (targetm.have_ctors_dtors)
929 (* targetm.asm_out.constructor) (XEXP (DECL_RTL (ctor), 0),
930 DEFAULT_INIT_PRIORITY);
931 }
932 \f
933 /* Perform file-level initialization. Read in data file, generate name
934 of graph file. */
935
936 void
937 coverage_init (const char *filename)
938 {
939 int len = strlen (filename);
940
941 /* Name of da file. */
942 da_file_name = xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
943 strcpy (da_file_name, filename);
944 strcat (da_file_name, GCOV_DATA_SUFFIX);
945
946 /* Name of bbg file. */
947 bbg_file_name = xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1);
948 strcpy (bbg_file_name, filename);
949 strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
950
951 read_counts_file ();
952 }
953
954 /* Performs file-level cleanup. Close graph file, generate coverage
955 variables and constructor. */
956
957 void
958 coverage_finish (void)
959 {
960 create_coverage ();
961 if (bbg_file_opened)
962 {
963 int error = gcov_close ();
964
965 if (error)
966 unlink (bbg_file_name);
967 if (!local_tick)
968 /* Only remove the da file, if we cannot stamp it. If we can
969 stamp it, libgcov will DTRT. */
970 unlink (da_file_name);
971 }
972 }
973
974 #include "gt-coverage.h"