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