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