]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | |
9dcd6f09 | 13 | Software Foundation; either version 3, or (at your option) any later |
ca29da43 NS |
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 | |
9dcd6f09 NC |
22 | along 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 | ||
49 | struct 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. */ | |
58 | typedef 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 | ||
74 | static struct function_list *functions_head = 0; | |
75 | static struct function_list **functions_tail = &functions_head; | |
6d70e6be | 76 | static unsigned no_coverage = 0; |
ca29da43 | 77 | |
cdb23767 NS |
78 | /* Cumulative counter information for whole program. */ |
79 | static unsigned prg_ctr_mask; /* Mask of counter types generated. */ | |
6d70e6be | 80 | static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated. */ |
ca29da43 | 81 | |
cdb23767 | 82 | /* Counter information for current function. */ |
71c0e7fc | 83 | static unsigned fn_ctr_mask; /* Mask of counters used. */ |
6d70e6be NS |
84 | static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */ |
85 | static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */ | |
ca29da43 NS |
86 | |
87 | /* Name of the output file for coverage output file. */ | |
88 | static char *bbg_file_name; | |
89 | static unsigned bbg_file_opened; | |
90 | static int bbg_function_announced; | |
91 | ||
92 | /* Name of the count data file. */ | |
93 | static char *da_file_name; | |
94 | ||
95 | /* Hash table of count data. */ | |
96 | static htab_t counts_hash = NULL; | |
97 | ||
6de9cd9a DN |
98 | /* Trees representing the counter table arrays. */ |
99 | static 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 | 103 | static GTY(()) rtx ctr_labels[GCOV_COUNTERS]; |
ca29da43 | 104 | |
09780dfb | 105 | /* The names of merge functions for counters. */ |
9b514d25 NS |
106 | static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS; |
107 | static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES; | |
09780dfb | 108 | |
ca29da43 | 109 | /* Forward declarations. */ |
159b3be1 AJ |
110 | static hashval_t htab_counts_entry_hash (const void *); |
111 | static int htab_counts_entry_eq (const void *, const void *); | |
112 | static void htab_counts_entry_del (void *); | |
113 | static void read_counts_file (void); | |
114 | static unsigned compute_checksum (void); | |
20c361f3 | 115 | static unsigned coverage_checksum_string (unsigned, const char *); |
159b3be1 AJ |
116 | static tree build_fn_info_type (unsigned); |
117 | static tree build_fn_info_value (const struct function_list *, tree); | |
118 | static tree build_ctr_info_type (void); | |
119 | static tree build_ctr_info_value (unsigned, tree); | |
120 | static tree build_gcov_info (void); | |
121 | static void create_coverage (void); | |
251e2ff2 RS |
122 | \f |
123 | /* Return the type node for gcov_type. */ | |
124 | ||
125 | tree | |
126 | get_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 |
133 | static tree |
134 | get_gcov_unsigned_t (void) | |
135 | { | |
136 | return lang_hooks.types.type_for_size (32, true); | |
137 | } | |
ca29da43 NS |
138 | \f |
139 | static hashval_t | |
159b3be1 | 140 | htab_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 | ||
147 | static int | |
159b3be1 | 148 | htab_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 | ||
156 | static void | |
159b3be1 | 157 | htab_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 | ||
167 | static void | |
159b3be1 | 168 | read_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 | ||
322 | gcov_type * | |
cdb23767 NS |
323 | get_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 |
400 | int |
401 | coverage_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 | ||
433 | tree | |
434 | tree_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 | |
449 | static unsigned | |
20c361f3 | 450 | coverage_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 | ||
509 | static unsigned | |
159b3be1 | 510 | compute_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 | ||
528 | int | |
159b3be1 | 529 | coverage_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 | ||
571 | void | |
159b3be1 | 572 | coverage_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 | 608 | static tree |
159b3be1 | 609 | build_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 | 641 | static tree |
159b3be1 | 642 | build_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 | 682 | static tree |
159b3be1 | 683 | build_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 | 719 | static tree |
159b3be1 | 720 | build_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 | 777 | static tree |
159b3be1 | 778 | build_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 | ||
918 | static void | |
159b3be1 | 919 | create_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 | |
961 | void | |
159b3be1 | 962 | coverage_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 | ||
982 | void | |
159b3be1 | 983 | coverage_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" |