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