Branch data Line data Source code
1 : : /* Read and write coverage files, and associated functionality.
2 : : Copyright (C) 1990-2024 Free Software Foundation, Inc.
3 : : Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
4 : : based on some ideas from Dain Samples of UC Berkeley.
5 : : Further mangling by Bob Manson, Cygnus Support.
6 : : Further mangled by Nathan Sidwell, CodeSourcery
7 : :
8 : : This file is part of GCC.
9 : :
10 : : GCC is free software; you can redistribute it and/or modify it under
11 : : the terms of the GNU General Public License as published by the Free
12 : : Software Foundation; either version 3, or (at your option) any later
13 : : version.
14 : :
15 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 : : for more details.
19 : :
20 : : You should have received a copy of the GNU General Public License
21 : : along with GCC; see the file COPYING3. If not see
22 : : <http://www.gnu.org/licenses/>. */
23 : :
24 : :
25 : : #define GCOV_LINKAGE
26 : :
27 : : #include "config.h"
28 : : #include "system.h"
29 : : #include "coretypes.h"
30 : : #include "backend.h"
31 : : #include "target.h"
32 : : #include "rtl.h"
33 : : #include "tree.h"
34 : : #include "tree-pass.h"
35 : : #include "memmodel.h"
36 : : #include "tm_p.h"
37 : : #include "stringpool.h"
38 : : #include "cgraph.h"
39 : : #include "coverage.h"
40 : : #include "diagnostic-core.h"
41 : : #include "fold-const.h"
42 : : #include "stor-layout.h"
43 : : #include "output.h"
44 : : #include "toplev.h"
45 : : #include "langhooks.h"
46 : : #include "tree-iterator.h"
47 : : #include "context.h"
48 : : #include "pass_manager.h"
49 : : #include "intl.h"
50 : : #include "auto-profile.h"
51 : : #include "profile.h"
52 : : #include "diagnostic.h"
53 : : #include "varasm.h"
54 : : #include "file-prefix-map.h"
55 : :
56 : : #include "gcov-io.cc"
57 : :
58 : : struct GTY((chain_next ("%h.next"))) coverage_data
59 : : {
60 : : struct coverage_data *next; /* next function */
61 : : unsigned ident; /* function ident */
62 : : unsigned lineno_checksum; /* function lineno checksum */
63 : : unsigned cfg_checksum; /* function cfg checksum */
64 : : tree fn_decl; /* the function decl */
65 : : tree ctr_vars[GCOV_COUNTERS]; /* counter variables. */
66 : : };
67 : :
68 : : /* Counts information for a function. */
69 : : struct counts_entry : pointer_hash <counts_entry>
70 : : {
71 : : /* We hash by */
72 : : unsigned ident;
73 : : unsigned ctr;
74 : :
75 : : /* Store */
76 : : unsigned lineno_checksum;
77 : : unsigned cfg_checksum;
78 : : gcov_type *counts;
79 : : unsigned n_counts;
80 : :
81 : : /* hash_table support. */
82 : : static inline hashval_t hash (const counts_entry *);
83 : : static int equal (const counts_entry *, const counts_entry *);
84 : : static void remove (counts_entry *);
85 : : };
86 : :
87 : : static GTY(()) struct coverage_data *functions_head = 0;
88 : : static struct coverage_data **functions_tail = &functions_head;
89 : : static unsigned no_coverage = 0;
90 : :
91 : : /* Cumulative counter information for whole program. */
92 : : static unsigned prg_ctr_mask; /* Mask of counter types generated. */
93 : :
94 : : /* Counter information for current function. */
95 : : static unsigned fn_ctr_mask; /* Mask of counters used. */
96 : : static GTY(()) tree fn_v_ctrs[GCOV_COUNTERS]; /* counter variables. */
97 : : static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */
98 : : static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */
99 : :
100 : : /* Coverage info VAR_DECL and function info type nodes. */
101 : : static GTY(()) tree gcov_info_var;
102 : : static GTY(()) tree gcov_fn_info_type;
103 : : static GTY(()) tree gcov_fn_info_ptr_type;
104 : :
105 : : /* Name of the notes (gcno) output file. The "bbg" prefix is for
106 : : historical reasons, when the notes file contained only the
107 : : basic block graph notes.
108 : : If this is NULL we're not writing to the notes file. */
109 : : static char *bbg_file_name;
110 : :
111 : : /* File stamp for notes file. */
112 : : static unsigned bbg_file_stamp;
113 : :
114 : : /* Name of the count data (gcda) file. */
115 : : static char *da_file_name;
116 : :
117 : : /* The names of merge functions for counters. */
118 : : #define STR(str) #str
119 : : #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) STR(__gcov_merge ## FN_TYPE),
120 : : static const char *const ctr_merge_functions[GCOV_COUNTERS] = {
121 : : #include "gcov-counter.def"
122 : : };
123 : : #undef DEF_GCOV_COUNTER
124 : : #undef STR
125 : :
126 : : #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) NAME,
127 : : static const char *const ctr_names[GCOV_COUNTERS] = {
128 : : #include "gcov-counter.def"
129 : : };
130 : : #undef DEF_GCOV_COUNTER
131 : :
132 : : /* Forward declarations. */
133 : : static tree build_var (tree, tree, int);
134 : :
135 : : /* Return the type node for gcov_type. */
136 : :
137 : : tree
138 : 15896 : get_gcov_type (void)
139 : : {
140 : 15896 : scalar_int_mode mode
141 : 15896 : = smallest_int_mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32);
142 : 15896 : return lang_hooks.types.type_for_mode (mode, false);
143 : : }
144 : :
145 : : /* Return the type node for gcov_unsigned_t. */
146 : :
147 : : static tree
148 : 11223 : get_gcov_unsigned_t (void)
149 : : {
150 : 11223 : scalar_int_mode mode = smallest_int_mode_for_size (32);
151 : 11223 : return lang_hooks.types.type_for_mode (mode, true);
152 : : }
153 : :
154 : : inline hashval_t
155 : 10795 : counts_entry::hash (const counts_entry *entry)
156 : : {
157 : 10795 : return entry->ident * GCOV_COUNTERS + entry->ctr;
158 : : }
159 : :
160 : : inline int
161 : 9697 : counts_entry::equal (const counts_entry *entry1, const counts_entry *entry2)
162 : : {
163 : 9697 : return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
164 : : }
165 : :
166 : : inline void
167 : 0 : counts_entry::remove (counts_entry *entry)
168 : : {
169 : 0 : free (entry->counts);
170 : 0 : free (entry);
171 : 0 : }
172 : :
173 : : /* Hash table of count data. */
174 : : static hash_table<counts_entry> *counts_hash;
175 : :
176 : : /* Read in the counts file, if available. */
177 : :
178 : : static void
179 : 168 : read_counts_file (void)
180 : : {
181 : 168 : gcov_unsigned_t fn_ident = 0;
182 : 168 : gcov_unsigned_t tag;
183 : 168 : int is_error = 0;
184 : 168 : unsigned lineno_checksum = 0;
185 : 168 : unsigned cfg_checksum = 0;
186 : :
187 : 168 : if (!gcov_open (da_file_name, 1))
188 : : return;
189 : :
190 : 113 : if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
191 : : {
192 : 0 : warning (0, "%qs is not a gcov data file", da_file_name);
193 : 0 : gcov_close ();
194 : 0 : return;
195 : : }
196 : 113 : else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
197 : : {
198 : 0 : char v[4], e[4];
199 : :
200 : 0 : GCOV_UNSIGNED2STRING (v, tag);
201 : 0 : GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
202 : :
203 : 0 : warning (0, "%qs is version %q.*s, expected version %q.*s",
204 : : da_file_name, 4, v, 4, e);
205 : 0 : gcov_close ();
206 : 0 : return;
207 : : }
208 : :
209 : : /* Read the stamp, used for creating a generation count. */
210 : 113 : tag = gcov_read_unsigned ();
211 : 113 : bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
212 : :
213 : : /* Read checksum. */
214 : 113 : gcov_read_unsigned ();
215 : :
216 : 113 : counts_hash = new hash_table<counts_entry> (10);
217 : 1739 : while ((tag = gcov_read_unsigned ()))
218 : : {
219 : 1626 : gcov_unsigned_t length;
220 : 1626 : gcov_position_t offset;
221 : :
222 : 1626 : length = gcov_read_unsigned ();
223 : 1626 : offset = gcov_position ();
224 : 1626 : if (tag == GCOV_TAG_FUNCTION)
225 : : {
226 : 478 : if (length)
227 : : {
228 : 478 : fn_ident = gcov_read_unsigned ();
229 : 478 : lineno_checksum = gcov_read_unsigned ();
230 : 478 : cfg_checksum = gcov_read_unsigned ();
231 : : }
232 : : else
233 : : fn_ident = lineno_checksum = cfg_checksum = 0;
234 : : }
235 : 1148 : else if (tag == GCOV_TAG_OBJECT_SUMMARY)
236 : : {
237 : 113 : profile_info = XCNEW (gcov_summary);
238 : 113 : profile_info->runs = gcov_read_unsigned ();
239 : 113 : profile_info->sum_max = gcov_read_unsigned ();
240 : : }
241 : 1035 : else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
242 : : {
243 : 1035 : counts_entry **slot, *entry, elt;
244 : 1035 : int read_length = (int)length;
245 : 1035 : length = read_length > 0 ? read_length : 0;
246 : 1035 : unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (read_length));
247 : 1035 : unsigned ix;
248 : :
249 : 1035 : elt.ident = fn_ident;
250 : 1035 : elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
251 : :
252 : 1035 : slot = counts_hash->find_slot (&elt, INSERT);
253 : 1035 : entry = *slot;
254 : 1035 : if (!entry)
255 : : {
256 : 1035 : *slot = entry = XCNEW (counts_entry);
257 : 1035 : entry->ident = fn_ident;
258 : 1035 : entry->ctr = elt.ctr;
259 : 1035 : entry->lineno_checksum = lineno_checksum;
260 : 1035 : entry->cfg_checksum = cfg_checksum;
261 : 1035 : entry->counts = XCNEWVEC (gcov_type, n_counts);
262 : 1035 : entry->n_counts = n_counts;
263 : : }
264 : 0 : else if (entry->lineno_checksum != lineno_checksum
265 : 0 : || entry->cfg_checksum != cfg_checksum)
266 : : {
267 : 0 : error ("profile data for function %u is corrupted", fn_ident);
268 : 0 : error ("checksum is (%x,%x) instead of (%x,%x)",
269 : : entry->lineno_checksum, entry->cfg_checksum,
270 : : lineno_checksum, cfg_checksum);
271 : 0 : delete counts_hash;
272 : 0 : counts_hash = NULL;
273 : 0 : break;
274 : : }
275 : 1035 : if (read_length > 0)
276 : 2800 : for (ix = 0; ix != n_counts; ix++)
277 : 2099 : entry->counts[ix] = gcov_read_counter ();
278 : : }
279 : 1626 : gcov_sync (offset, length);
280 : 3252 : if ((is_error = gcov_is_error ()))
281 : : {
282 : 0 : error (is_error < 0
283 : : ? G_("%qs has overflowed")
284 : : : G_("%qs is corrupted"),
285 : : da_file_name);
286 : 0 : delete counts_hash;
287 : 0 : counts_hash = NULL;
288 : 0 : break;
289 : : }
290 : : }
291 : :
292 : 113 : gcov_close ();
293 : : }
294 : :
295 : : /* Returns the counters for a particular tag. */
296 : :
297 : : gcov_type *
298 : 1130 : get_coverage_counts (unsigned counter, unsigned cfg_checksum,
299 : : unsigned lineno_checksum, unsigned int n_counts)
300 : : {
301 : 1130 : counts_entry *entry, elt;
302 : :
303 : : /* No hash table, no counts. */
304 : 1130 : if (!counts_hash)
305 : : {
306 : 204 : static int warned = 0;
307 : :
308 : 204 : if (!warned++)
309 : : {
310 : 47 : warning (OPT_Wmissing_profile,
311 : : "%qs profile count data file not found",
312 : : da_file_name);
313 : 47 : if (dump_enabled_p ())
314 : : {
315 : 7 : dump_user_location_t loc
316 : 7 : = dump_user_location_t::from_location_t (input_location);
317 : 7 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
318 : : "file %s not found, %s\n", da_file_name,
319 : 7 : (flag_guess_branch_prob
320 : : ? "execution counts estimated"
321 : : : "execution counts assumed to be zero"));
322 : : }
323 : : }
324 : 204 : return NULL;
325 : : }
326 : 926 : if (param_profile_func_internal_id)
327 : 0 : elt.ident = current_function_funcdef_no + 1;
328 : : else
329 : : {
330 : 926 : gcc_assert (coverage_node_map_initialized_p ());
331 : 926 : elt.ident = cgraph_node::get (current_function_decl)->profile_id;
332 : : }
333 : 926 : elt.ctr = counter;
334 : 926 : entry = counts_hash->find (&elt);
335 : 926 : if (!entry)
336 : : {
337 : 21 : if (counter == GCOV_COUNTER_ARCS)
338 : 1 : warning_at (DECL_SOURCE_LOCATION (current_function_decl),
339 : : OPT_Wmissing_profile,
340 : : "profile for function %qD not found in profile data",
341 : : current_function_decl);
342 : : /* The function was not emitted, or is weak and not chosen in the
343 : : final executable. Silently fail, because there's nothing we
344 : : can do about it. */
345 : 21 : return NULL;
346 : : }
347 : :
348 : 905 : if (entry->cfg_checksum != cfg_checksum
349 : 903 : || (counter != GCOV_COUNTER_V_INDIR
350 : 903 : && counter != GCOV_COUNTER_V_TOPN
351 : 837 : && entry->n_counts != n_counts))
352 : : {
353 : 2 : static int warned = 0;
354 : 2 : bool warning_printed = false;
355 : :
356 : 2 : if (entry->n_counts != n_counts)
357 : 1 : warning_printed =
358 : 1 : warning_at (DECL_SOURCE_LOCATION (current_function_decl),
359 : : OPT_Wcoverage_mismatch,
360 : : "number of counters in profile data for function %qD "
361 : : "does not match "
362 : : "its profile data (counter %qs, expected %i and have %i)",
363 : : current_function_decl,
364 : 1 : ctr_names[counter], entry->n_counts, n_counts);
365 : : else
366 : 1 : warning_printed =
367 : 1 : warning_at (DECL_SOURCE_LOCATION (current_function_decl),
368 : : OPT_Wcoverage_mismatch,
369 : : "the control flow of function %qD does not match "
370 : : "its profile data (counter %qs)", current_function_decl,
371 : 1 : ctr_names[counter]);
372 : 2 : if (warning_printed && dump_enabled_p ())
373 : : {
374 : 0 : dump_user_location_t loc
375 : 0 : = dump_user_location_t::from_function_decl (current_function_decl);
376 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
377 : : "use -Wno-error=coverage-mismatch to tolerate "
378 : : "the mismatch but performance may drop if the "
379 : : "function is hot\n");
380 : :
381 : 0 : if (!seen_error ()
382 : 0 : && !warned++)
383 : : {
384 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
385 : : "coverage mismatch ignored\n");
386 : 0 : dump_printf (MSG_MISSED_OPTIMIZATION,
387 : 0 : flag_guess_branch_prob
388 : : ? G_("execution counts estimated\n")
389 : : : G_("execution counts assumed to be zero\n"));
390 : 0 : if (!flag_guess_branch_prob)
391 : 0 : dump_printf (MSG_MISSED_OPTIMIZATION,
392 : : "this can result in poorly optimized code\n");
393 : : }
394 : : }
395 : :
396 : 2 : return NULL;
397 : : }
398 : 903 : else if (entry->lineno_checksum != lineno_checksum)
399 : : {
400 : 8 : warning_at (DECL_SOURCE_LOCATION (current_function_decl),
401 : : OPT_Wcoverage_mismatch,
402 : : "source locations for function %qD have changed,"
403 : : " the profile data may be out of date",
404 : : current_function_decl);
405 : : }
406 : :
407 : 903 : return entry->counts;
408 : : }
409 : :
410 : : /* Allocate NUM counters of type COUNTER. Returns nonzero if the
411 : : allocation succeeded. */
412 : :
413 : : int
414 : 2407 : coverage_counter_alloc (unsigned counter, unsigned num)
415 : : {
416 : 2407 : if (no_coverage)
417 : : return 0;
418 : :
419 : 2407 : if (!num)
420 : : return 1;
421 : :
422 : 2384 : if (!fn_v_ctrs[counter])
423 : : {
424 : 2380 : tree array_type = build_array_type (get_gcov_type (), NULL_TREE);
425 : :
426 : 2380 : fn_v_ctrs[counter]
427 : 2380 : = build_var (current_function_decl, array_type, counter);
428 : : }
429 : :
430 : 2384 : fn_b_ctrs[counter] = fn_n_ctrs[counter];
431 : 2384 : fn_n_ctrs[counter] += num;
432 : :
433 : 2384 : fn_ctr_mask |= 1 << counter;
434 : 2384 : return 1;
435 : : }
436 : :
437 : : /* Generate a tree to access COUNTER NO. */
438 : :
439 : : tree
440 : 7822 : tree_coverage_counter_ref (unsigned counter, unsigned no)
441 : : {
442 : 7822 : tree gcov_type_node = get_gcov_type ();
443 : :
444 : 7822 : gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
445 : :
446 : 7822 : no += fn_b_ctrs[counter];
447 : :
448 : : /* "no" here is an array index, scaled to bytes later. */
449 : 7822 : return build4 (ARRAY_REF, gcov_type_node, fn_v_ctrs[counter],
450 : 7822 : build_int_cst (integer_type_node, no), NULL, NULL);
451 : : }
452 : :
453 : : /* Generate a tree to access the address of COUNTER NO. */
454 : :
455 : : tree
456 : 143 : tree_coverage_counter_addr (unsigned counter, unsigned no)
457 : : {
458 : 143 : tree gcov_type_node = get_gcov_type ();
459 : :
460 : 143 : gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
461 : 143 : no += fn_b_ctrs[counter];
462 : :
463 : : /* "no" here is an array index, scaled to bytes later. */
464 : 143 : return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node,
465 : : fn_v_ctrs[counter],
466 : : build_int_cst (integer_type_node, no),
467 : : NULL, NULL));
468 : : }
469 : :
470 : :
471 : : /* Generate a checksum for a string. CHKSUM is the current
472 : : checksum. */
473 : :
474 : : static unsigned
475 : 7280 : coverage_checksum_string (unsigned chksum, const char *string)
476 : : {
477 : 7280 : int i;
478 : 7280 : 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 : 297000 : for (i = 0; string[i]; i++)
485 : : {
486 : 289798 : int offset = 0;
487 : 289798 : if (startswith (string + i, "_GLOBAL__N_"))
488 : 28 : offset = 11;
489 : 289798 : if (startswith (string + i, "_GLOBAL__"))
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 : 289720 : if (offset)
498 : : {
499 : 772 : for (i = i + offset; string[i]; i++)
500 : 694 : if (string[i]=='_')
501 : : {
502 : : int y;
503 : :
504 : 202 : for (y = 1; y < 9; y++)
505 : 202 : if (!(string[i + y] >= '0' && string[i + y] <= '9')
506 : 138 : && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
507 : : break;
508 : 136 : if (y != 9 || string[i + 9] != '_')
509 : 136 : continue;
510 : 0 : for (y = 10; y < 18; y++)
511 : 0 : if (!(string[i + y] >= '0' && string[i + y] <= '9')
512 : 0 : && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
513 : : break;
514 : 0 : if (y != 18)
515 : 0 : continue;
516 : 0 : if (!dup)
517 : 0 : string = dup = xstrdup (string);
518 : 0 : for (y = 10; y < 18; y++)
519 : 0 : dup[i + y] = '0';
520 : : }
521 : : break;
522 : : }
523 : : }
524 : :
525 : 7280 : chksum = crc32_string (chksum, string);
526 : 7280 : free (dup);
527 : :
528 : 7280 : return chksum;
529 : : }
530 : :
531 : : /* Compute checksum for the current function. We generate a CRC32. */
532 : :
533 : : unsigned
534 : 2266 : coverage_compute_lineno_checksum (void)
535 : : {
536 : 2266 : expanded_location xloc
537 : 2266 : = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
538 : 2266 : unsigned chksum = xloc.line;
539 : :
540 : 2266 : if (xloc.file)
541 : 2266 : chksum = coverage_checksum_string (chksum, xloc.file);
542 : 2266 : chksum = coverage_checksum_string
543 : 2266 : (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
544 : :
545 : 2266 : return chksum;
546 : : }
547 : :
548 : : /* Compute profile ID. This is better to be unique in whole program. */
549 : :
550 : : unsigned
551 : 2290 : coverage_compute_profile_id (struct cgraph_node *n)
552 : : {
553 : 2290 : unsigned chksum;
554 : :
555 : : /* Externally visible symbols have unique name. */
556 : 2290 : if (TREE_PUBLIC (n->decl) || DECL_EXTERNAL (n->decl) || n->unique_name)
557 : : {
558 : 2061 : chksum = coverage_checksum_string
559 : 2061 : (0, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
560 : : }
561 : : else
562 : : {
563 : 229 : expanded_location xloc
564 : 229 : = expand_location (DECL_SOURCE_LOCATION (n->decl));
565 : 229 : bool use_name_only = (param_profile_func_internal_id == 0);
566 : :
567 : 229 : chksum = (use_name_only ? 0 : xloc.line);
568 : 229 : if (xloc.file)
569 : 229 : chksum = coverage_checksum_string (chksum, xloc.file);
570 : 229 : chksum = coverage_checksum_string
571 : 229 : (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
572 : 229 : if (!use_name_only && first_global_object_name)
573 : 0 : chksum = coverage_checksum_string
574 : 0 : (chksum, first_global_object_name);
575 : 229 : char *base_name = xstrdup (aux_base_name);
576 : 229 : if (endswith (base_name, ".gk"))
577 : 1 : base_name[strlen (base_name) - 3] = '\0';
578 : 229 : chksum = coverage_checksum_string (chksum, base_name);
579 : 229 : free (base_name);
580 : : }
581 : :
582 : : /* Non-negative integers are hopefully small enough to fit in all targets.
583 : : Gcov file formats wants non-zero function IDs. */
584 : 2290 : chksum = chksum & 0x7fffffff;
585 : 2290 : return chksum + (!chksum);
586 : : }
587 : :
588 : : /* Compute cfg checksum for the function FN given as argument.
589 : : The checksum is calculated carefully so that
590 : : source code changes that doesn't affect the control flow graph
591 : : won't change the checksum.
592 : : This is to make the profile data useable across source code change.
593 : : The downside of this is that the compiler may use potentially
594 : : wrong profile data - that the source code change has non-trivial impact
595 : : on the validity of profile data (e.g. the reversed condition)
596 : : but the compiler won't detect the change and use the wrong profile data. */
597 : :
598 : : unsigned
599 : 978709 : coverage_compute_cfg_checksum (struct function *fn)
600 : : {
601 : 978709 : basic_block bb;
602 : 978709 : unsigned chksum = n_basic_blocks_for_fn (fn);
603 : :
604 : 6669051 : FOR_EACH_BB_FN (bb, fn)
605 : : {
606 : 5690342 : edge e;
607 : 5690342 : edge_iterator ei;
608 : 5690342 : chksum = crc32_byte (chksum, bb->index);
609 : 13265722 : FOR_EACH_EDGE (e, ei, bb->succs)
610 : : {
611 : 7575380 : chksum = crc32_byte (chksum, e->dest->index);
612 : : }
613 : : }
614 : :
615 : 978709 : return chksum;
616 : : }
617 : :
618 : : /* Begin output to the notes file for the current function.
619 : : Writes the function header. Returns nonzero if data should be output. */
620 : :
621 : : int
622 : 2273 : coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum)
623 : : {
624 : : /* We don't need to output .gcno file unless we're under -ftest-coverage
625 : : (e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
626 : 2273 : if (no_coverage || !bbg_file_name)
627 : : return 0;
628 : :
629 : 859 : expanded_location startloc
630 : 859 : = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
631 : :
632 : : /* Announce function */
633 : 859 : unsigned long offset = gcov_write_tag (GCOV_TAG_FUNCTION);
634 : 859 : if (param_profile_func_internal_id)
635 : 0 : gcov_write_unsigned (current_function_funcdef_no + 1);
636 : : else
637 : : {
638 : 859 : gcc_assert (coverage_node_map_initialized_p ());
639 : 859 : gcov_write_unsigned (
640 : 859 : cgraph_node::get (current_function_decl)->profile_id);
641 : : }
642 : :
643 : 859 : gcov_write_unsigned (lineno_checksum);
644 : 859 : gcov_write_unsigned (cfg_checksum);
645 : 859 : gcov_write_string (IDENTIFIER_POINTER
646 : : (DECL_ASSEMBLER_NAME (current_function_decl)));
647 : 1718 : gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
648 : 45 : && !DECL_FUNCTION_VERSIONED (current_function_decl)
649 : 904 : && !DECL_LAMBDA_FUNCTION_P (current_function_decl));
650 : 859 : gcov_write_filename (remap_profile_filename (startloc.file));
651 : 859 : gcov_write_unsigned (startloc.line);
652 : 859 : gcov_write_unsigned (startloc.column);
653 : :
654 : 859 : expanded_location endloc = expand_location (cfun->function_end_locus);
655 : :
656 : : /* Function can start in a single file and end in another one. */
657 : 1718 : int end_line
658 : 859 : = endloc.file == startloc.file ? endloc.line : startloc.line;
659 : 1718 : int end_column
660 : 859 : = endloc.file == startloc.file ? endloc.column: startloc.column;
661 : :
662 : 859 : if (startloc.line > end_line)
663 : : {
664 : 1 : warning_at (DECL_SOURCE_LOCATION (current_function_decl),
665 : : OPT_Wcoverage_invalid_line_number,
666 : : "function starts on a higher line number than it ends");
667 : 1 : end_line = startloc.line;
668 : 1 : end_column = startloc.column;
669 : : }
670 : :
671 : 859 : gcov_write_unsigned (end_line);
672 : 859 : gcov_write_unsigned (end_column);
673 : 859 : gcov_write_length (offset);
674 : :
675 : 1718 : return !gcov_is_error ();
676 : : }
677 : :
678 : : /* Finish coverage data for the current function. Verify no output
679 : : error has occurred. Save function coverage counts. */
680 : :
681 : : void
682 : 2273 : coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
683 : : {
684 : 2273 : unsigned i;
685 : :
686 : 3132 : if (bbg_file_name && gcov_is_error ())
687 : : {
688 : 0 : warning (0, "error writing %qs", bbg_file_name);
689 : 0 : unlink (bbg_file_name);
690 : 0 : bbg_file_name = NULL;
691 : : }
692 : :
693 : 2273 : if (fn_ctr_mask)
694 : : {
695 : 1686 : struct coverage_data *item = 0;
696 : :
697 : 1686 : item = ggc_alloc<coverage_data> ();
698 : :
699 : 1686 : if (param_profile_func_internal_id)
700 : 0 : item->ident = current_function_funcdef_no + 1;
701 : : else
702 : : {
703 : 1686 : gcc_assert (coverage_node_map_initialized_p ());
704 : 1686 : item->ident = cgraph_node::get (cfun->decl)->profile_id;
705 : : }
706 : :
707 : 1686 : item->lineno_checksum = lineno_checksum;
708 : 1686 : item->cfg_checksum = cfg_checksum;
709 : :
710 : 1686 : item->fn_decl = current_function_decl;
711 : 1686 : item->next = 0;
712 : 1686 : *functions_tail = item;
713 : 1686 : functions_tail = &item->next;
714 : :
715 : 16860 : for (i = 0; i != GCOV_COUNTERS; i++)
716 : : {
717 : 15174 : tree var = fn_v_ctrs[i];
718 : :
719 : 15174 : if (item)
720 : 15174 : item->ctr_vars[i] = var;
721 : 15174 : if (var)
722 : : {
723 : 2380 : tree array_type = build_index_type (size_int (fn_n_ctrs[i] - 1));
724 : 2380 : array_type = build_array_type (get_gcov_type (), array_type);
725 : 2380 : TREE_TYPE (var) = array_type;
726 : 2380 : DECL_SIZE (var) = TYPE_SIZE (array_type);
727 : 2380 : DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (array_type);
728 : 2380 : varpool_node::finalize_decl (var);
729 : : }
730 : :
731 : 15174 : fn_b_ctrs[i] = fn_n_ctrs[i] = 0;
732 : 15174 : fn_v_ctrs[i] = NULL_TREE;
733 : : }
734 : 1686 : prg_ctr_mask |= fn_ctr_mask;
735 : 1686 : fn_ctr_mask = 0;
736 : : }
737 : 2273 : }
738 : :
739 : : /* Remove coverage file if opened. */
740 : :
741 : : void
742 : 26601 : coverage_remove_note_file (void)
743 : : {
744 : 26601 : if (bbg_file_name)
745 : : {
746 : 0 : gcov_close ();
747 : 0 : unlink (bbg_file_name);
748 : : }
749 : 26601 : }
750 : :
751 : : /* Build a coverage variable of TYPE for function FN_DECL. If COUNTER
752 : : >= 0 it is a counter array, otherwise it is the function structure. */
753 : :
754 : : static tree
755 : 4066 : build_var (tree fn_decl, tree type, int counter)
756 : : {
757 : 4066 : tree var = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE, type);
758 : 4066 : const char *fn_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl));
759 : 4066 : char *buf;
760 : 4066 : size_t fn_name_len, len;
761 : :
762 : 4066 : fn_name = targetm.strip_name_encoding (fn_name);
763 : 4066 : fn_name_len = strlen (fn_name);
764 : 4066 : buf = XALLOCAVEC (char, fn_name_len + 8 + sizeof (int) * 3);
765 : :
766 : 4066 : if (counter < 0)
767 : 1686 : strcpy (buf, "__gcov__");
768 : : else
769 : 2380 : sprintf (buf, "__gcov%u_", counter);
770 : 4066 : len = strlen (buf);
771 : 4066 : buf[len - 1] = symbol_table::symbol_suffix_separator ();
772 : 4066 : memcpy (buf + len, fn_name, fn_name_len + 1);
773 : 4066 : DECL_NAME (var) = get_identifier (buf);
774 : 4066 : TREE_STATIC (var) = 1;
775 : 4066 : TREE_ADDRESSABLE (var) = 1;
776 : 4066 : DECL_NONALIASED (var) = 1;
777 : 4066 : SET_DECL_ALIGN (var, TYPE_ALIGN (type));
778 : :
779 : 4066 : return var;
780 : : }
781 : :
782 : : /* Creates the gcov_fn_info RECORD_TYPE. */
783 : :
784 : : static void
785 : 400 : build_fn_info_type (tree type, unsigned counters, tree gcov_info_type)
786 : : {
787 : 400 : tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE);
788 : 400 : tree field, fields;
789 : 400 : tree array_type;
790 : :
791 : 400 : gcc_assert (counters);
792 : :
793 : : /* ctr_info::num */
794 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
795 : : get_gcov_unsigned_t ());
796 : 400 : fields = field;
797 : :
798 : : /* ctr_info::values */
799 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
800 : : build_pointer_type (get_gcov_type ()));
801 : 400 : DECL_CHAIN (field) = fields;
802 : 400 : fields = field;
803 : :
804 : 400 : finish_builtin_struct (ctr_info, "__gcov_ctr_info", fields, NULL_TREE);
805 : :
806 : : /* key */
807 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
808 : : build_pointer_type (build_qualified_type
809 : : (gcov_info_type, TYPE_QUAL_CONST)));
810 : 400 : fields = field;
811 : :
812 : : /* ident */
813 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
814 : : get_gcov_unsigned_t ());
815 : 400 : DECL_CHAIN (field) = fields;
816 : 400 : fields = field;
817 : :
818 : : /* lineno_checksum */
819 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
820 : : get_gcov_unsigned_t ());
821 : 400 : DECL_CHAIN (field) = fields;
822 : 400 : fields = field;
823 : :
824 : : /* cfg checksum */
825 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
826 : : get_gcov_unsigned_t ());
827 : 400 : DECL_CHAIN (field) = fields;
828 : 400 : fields = field;
829 : :
830 : 400 : array_type = build_index_type (size_int (counters - 1));
831 : 400 : array_type = build_array_type (ctr_info, array_type);
832 : :
833 : : /* counters */
834 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, array_type);
835 : 400 : DECL_CHAIN (field) = fields;
836 : 400 : fields = field;
837 : :
838 : 400 : finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
839 : 400 : }
840 : :
841 : : /* Returns a CONSTRUCTOR for a gcov_fn_info. DATA is
842 : : the coverage data for the function and TYPE is the gcov_fn_info
843 : : RECORD_TYPE. KEY is the object file key. */
844 : :
845 : : static tree
846 : 1686 : build_fn_info (const struct coverage_data *data, tree type, tree key)
847 : : {
848 : 1686 : tree fields = TYPE_FIELDS (type);
849 : 1686 : tree ctr_type;
850 : 1686 : unsigned ix;
851 : 1686 : vec<constructor_elt, va_gc> *v1 = NULL;
852 : 1686 : vec<constructor_elt, va_gc> *v2 = NULL;
853 : :
854 : : /* key */
855 : 1686 : CONSTRUCTOR_APPEND_ELT (v1, fields,
856 : : build1 (ADDR_EXPR, TREE_TYPE (fields), key));
857 : 1686 : fields = DECL_CHAIN (fields);
858 : :
859 : : /* ident */
860 : 1686 : CONSTRUCTOR_APPEND_ELT (v1, fields,
861 : : build_int_cstu (get_gcov_unsigned_t (),
862 : : data->ident));
863 : 1686 : fields = DECL_CHAIN (fields);
864 : :
865 : : /* lineno_checksum */
866 : 1686 : CONSTRUCTOR_APPEND_ELT (v1, fields,
867 : : build_int_cstu (get_gcov_unsigned_t (),
868 : : data->lineno_checksum));
869 : 1686 : fields = DECL_CHAIN (fields);
870 : :
871 : : /* cfg_checksum */
872 : 1686 : CONSTRUCTOR_APPEND_ELT (v1, fields,
873 : : build_int_cstu (get_gcov_unsigned_t (),
874 : : data->cfg_checksum));
875 : 1686 : fields = DECL_CHAIN (fields);
876 : :
877 : : /* counters */
878 : 1686 : ctr_type = TREE_TYPE (TREE_TYPE (fields));
879 : 16860 : for (ix = 0; ix != GCOV_COUNTERS; ix++)
880 : 15174 : if (prg_ctr_mask & (1 << ix))
881 : : {
882 : 2565 : vec<constructor_elt, va_gc> *ctr = NULL;
883 : 2565 : tree var = data->ctr_vars[ix];
884 : 2565 : unsigned count = 0;
885 : :
886 : 2565 : if (var)
887 : 2380 : count
888 : 2380 : = tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (var))))
889 : 2380 : + 1;
890 : :
891 : 2565 : CONSTRUCTOR_APPEND_ELT (ctr, TYPE_FIELDS (ctr_type),
892 : : build_int_cstu (get_gcov_unsigned_t (),
893 : : count));
894 : :
895 : 2565 : if (var)
896 : 2380 : CONSTRUCTOR_APPEND_ELT (ctr, DECL_CHAIN (TYPE_FIELDS (ctr_type)),
897 : : build_fold_addr_expr (var));
898 : :
899 : 2565 : CONSTRUCTOR_APPEND_ELT (v2, NULL, build_constructor (ctr_type, ctr));
900 : : }
901 : :
902 : 1686 : CONSTRUCTOR_APPEND_ELT (v1, fields,
903 : : build_constructor (TREE_TYPE (fields), v2));
904 : :
905 : 1686 : return build_constructor (type, v1);
906 : : }
907 : :
908 : : /* Create gcov_info struct. TYPE is the incomplete RECORD_TYPE to be
909 : : completed, and FN_INFO_PTR_TYPE is a pointer to the function info type. */
910 : :
911 : : static void
912 : 400 : build_info_type (tree type, tree fn_info_ptr_type)
913 : : {
914 : 400 : tree field, fields = NULL_TREE;
915 : 400 : tree merge_fn_type;
916 : :
917 : : /* Version ident */
918 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
919 : : get_gcov_unsigned_t ());
920 : 400 : DECL_CHAIN (field) = fields;
921 : 400 : fields = field;
922 : :
923 : : /* next pointer */
924 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
925 : : build_pointer_type (build_qualified_type
926 : : (type, TYPE_QUAL_CONST)));
927 : 400 : DECL_CHAIN (field) = fields;
928 : 400 : fields = field;
929 : :
930 : : /* stamp */
931 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
932 : : get_gcov_unsigned_t ());
933 : 400 : DECL_CHAIN (field) = fields;
934 : 400 : fields = field;
935 : :
936 : : /* Checksum. */
937 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
938 : : get_gcov_unsigned_t ());
939 : 400 : DECL_CHAIN (field) = fields;
940 : 400 : fields = field;
941 : :
942 : : /* Filename */
943 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
944 : : build_pointer_type (build_qualified_type
945 : : (char_type_node, TYPE_QUAL_CONST)));
946 : 400 : DECL_CHAIN (field) = fields;
947 : 400 : fields = field;
948 : :
949 : : /* merge fn array */
950 : 400 : merge_fn_type
951 : 400 : = build_function_type_list (void_type_node,
952 : : build_pointer_type (get_gcov_type ()),
953 : : get_gcov_unsigned_t (), NULL_TREE);
954 : 400 : merge_fn_type
955 : 400 : = build_array_type (build_pointer_type (merge_fn_type),
956 : 400 : build_index_type (size_int (GCOV_COUNTERS - 1)));
957 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
958 : : merge_fn_type);
959 : 400 : DECL_CHAIN (field) = fields;
960 : 400 : fields = field;
961 : :
962 : : /* n_functions */
963 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
964 : : get_gcov_unsigned_t ());
965 : 400 : DECL_CHAIN (field) = fields;
966 : 400 : fields = field;
967 : :
968 : : /* function_info pointer pointer */
969 : 400 : fn_info_ptr_type = build_pointer_type
970 : 400 : (build_qualified_type (fn_info_ptr_type, TYPE_QUAL_CONST));
971 : 400 : field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
972 : : fn_info_ptr_type);
973 : 400 : DECL_CHAIN (field) = fields;
974 : 400 : fields = field;
975 : :
976 : 400 : finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
977 : 400 : }
978 : :
979 : : /* Returns a CONSTRUCTOR for the gcov_info object. INFO_TYPE is the
980 : : gcov_info structure type, FN_ARY is the array of pointers to
981 : : function info objects. */
982 : :
983 : : static tree
984 : 400 : build_info (tree info_type, tree fn_ary, unsigned object_checksum)
985 : : {
986 : 400 : tree info_fields = TYPE_FIELDS (info_type);
987 : 400 : tree merge_fn_type, n_funcs;
988 : 400 : unsigned ix;
989 : 400 : tree filename_string;
990 : 400 : int da_file_name_len;
991 : 400 : vec<constructor_elt, va_gc> *v1 = NULL;
992 : 400 : vec<constructor_elt, va_gc> *v2 = NULL;
993 : :
994 : : /* Version ident */
995 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
996 : : build_int_cstu (TREE_TYPE (info_fields),
997 : : GCOV_VERSION));
998 : 400 : info_fields = DECL_CHAIN (info_fields);
999 : :
1000 : : /* next -- NULL */
1001 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
1002 : 400 : info_fields = DECL_CHAIN (info_fields);
1003 : :
1004 : : /* stamp */
1005 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1006 : : build_int_cstu (TREE_TYPE (info_fields),
1007 : : bbg_file_stamp));
1008 : 400 : info_fields = DECL_CHAIN (info_fields);
1009 : :
1010 : : /* Checksum. */
1011 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1012 : : build_int_cstu (TREE_TYPE (info_fields),
1013 : : object_checksum));
1014 : 400 : info_fields = DECL_CHAIN (info_fields);
1015 : :
1016 : : /* Filename */
1017 : 400 : da_file_name_len = strlen (da_file_name);
1018 : 400 : filename_string = build_string (da_file_name_len + 1, da_file_name);
1019 : 800 : TREE_TYPE (filename_string) = build_array_type
1020 : 400 : (char_type_node, build_index_type (size_int (da_file_name_len)));
1021 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1022 : : build1 (ADDR_EXPR, TREE_TYPE (info_fields),
1023 : : filename_string));
1024 : 400 : info_fields = DECL_CHAIN (info_fields);
1025 : :
1026 : : /* merge fn array -- NULL slots indicate unmeasured counters */
1027 : 400 : merge_fn_type = TREE_TYPE (TREE_TYPE (info_fields));
1028 : 4000 : for (ix = 0; ix != GCOV_COUNTERS; ix++)
1029 : : {
1030 : 3600 : tree ptr = null_pointer_node;
1031 : :
1032 : 3600 : if ((1u << ix) & prg_ctr_mask)
1033 : : {
1034 : 711 : tree merge_fn = build_decl (BUILTINS_LOCATION,
1035 : : FUNCTION_DECL,
1036 : 711 : get_identifier (ctr_merge_functions[ix]),
1037 : 711 : TREE_TYPE (merge_fn_type));
1038 : 711 : DECL_EXTERNAL (merge_fn) = 1;
1039 : 711 : TREE_PUBLIC (merge_fn) = 1;
1040 : 711 : DECL_ARTIFICIAL (merge_fn) = 1;
1041 : 711 : TREE_NOTHROW (merge_fn) = 1;
1042 : : /* Initialize assembler name so we can stream out. */
1043 : 711 : DECL_ASSEMBLER_NAME (merge_fn);
1044 : 711 : ptr = build1 (ADDR_EXPR, merge_fn_type, merge_fn);
1045 : : }
1046 : 3600 : CONSTRUCTOR_APPEND_ELT (v2, NULL, ptr);
1047 : : }
1048 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1049 : : build_constructor (TREE_TYPE (info_fields), v2));
1050 : 400 : info_fields = DECL_CHAIN (info_fields);
1051 : :
1052 : : /* n_functions */
1053 : 400 : n_funcs = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (fn_ary)));
1054 : 400 : n_funcs = fold_build2 (PLUS_EXPR, TREE_TYPE (info_fields),
1055 : : n_funcs, size_one_node);
1056 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields, n_funcs);
1057 : 400 : info_fields = DECL_CHAIN (info_fields);
1058 : :
1059 : : /* functions */
1060 : 400 : CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1061 : : build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary));
1062 : 400 : info_fields = DECL_CHAIN (info_fields);
1063 : :
1064 : 400 : gcc_assert (!info_fields);
1065 : 400 : return build_constructor (info_type, v1);
1066 : : }
1067 : :
1068 : : /* Generate the constructor function to call __gcov_init. */
1069 : :
1070 : : static void
1071 : 398 : build_init_ctor (tree gcov_info_type)
1072 : : {
1073 : 398 : tree ctor, stmt, init_fn;
1074 : :
1075 : : /* Build a decl for __gcov_init. */
1076 : 398 : init_fn = build_pointer_type (gcov_info_type);
1077 : 398 : init_fn = build_function_type_list (void_type_node, init_fn, NULL);
1078 : 398 : init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
1079 : : get_identifier ("__gcov_init"), init_fn);
1080 : 398 : TREE_PUBLIC (init_fn) = 1;
1081 : 398 : DECL_EXTERNAL (init_fn) = 1;
1082 : 398 : DECL_ASSEMBLER_NAME (init_fn);
1083 : :
1084 : : /* Generate a call to __gcov_init(&gcov_info). */
1085 : 398 : ctor = NULL;
1086 : 398 : stmt = build_fold_addr_expr (gcov_info_var);
1087 : 398 : stmt = build_call_expr (init_fn, 1, stmt);
1088 : 398 : append_to_statement_list (stmt, &ctor);
1089 : :
1090 : : /* Generate a constructor to run it. */
1091 : 398 : int priority = SUPPORTS_INIT_PRIORITY
1092 : : ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
1093 : 398 : cgraph_build_static_cdtor ('I', ctor, priority);
1094 : 398 : }
1095 : :
1096 : : /* Generate the destructor function to call __gcov_exit. */
1097 : :
1098 : : static void
1099 : 398 : build_gcov_exit_decl (void)
1100 : : {
1101 : 398 : tree init_fn = build_function_type_list (void_type_node, NULL);
1102 : 398 : init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
1103 : : get_identifier ("__gcov_exit"), init_fn);
1104 : 398 : TREE_PUBLIC (init_fn) = 1;
1105 : 398 : DECL_EXTERNAL (init_fn) = 1;
1106 : 398 : DECL_ASSEMBLER_NAME (init_fn);
1107 : :
1108 : : /* Generate a call to __gcov_exit (). */
1109 : 398 : tree dtor = NULL;
1110 : 398 : tree stmt = build_call_expr (init_fn, 0);
1111 : 398 : append_to_statement_list (stmt, &dtor);
1112 : :
1113 : : /* Generate a destructor to run it. */
1114 : 398 : int priority = SUPPORTS_INIT_PRIORITY
1115 : : ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
1116 : :
1117 : 398 : cgraph_build_static_cdtor ('D', dtor, priority);
1118 : 398 : }
1119 : :
1120 : : /* Generate the pointer to the gcov_info_var in a dedicated section. */
1121 : :
1122 : : static void
1123 : 2 : build_gcov_info_var_registration (tree gcov_info_type)
1124 : : {
1125 : 2 : tree var = build_decl (BUILTINS_LOCATION,
1126 : : VAR_DECL, NULL_TREE,
1127 : : build_pointer_type (gcov_info_type));
1128 : 2 : TREE_STATIC (var) = 1;
1129 : 2 : TREE_READONLY (var) = 1;
1130 : 2 : char name_buf[32];
1131 : 2 : ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 2);
1132 : 2 : DECL_NAME (var) = get_identifier (name_buf);
1133 : 2 : get_section (profile_info_section, SECTION_UNNAMED, NULL);
1134 : 2 : set_decl_section_name (var, profile_info_section);
1135 : 2 : mark_decl_referenced (var);
1136 : 2 : DECL_INITIAL (var) = build_fold_addr_expr (gcov_info_var);
1137 : 2 : varpool_node::finalize_decl (var);
1138 : 2 : }
1139 : :
1140 : : /* Create the gcov_info types and object. Generate the constructor
1141 : : function to call __gcov_init. Does not generate the initializer
1142 : : for the object. Returns TRUE if coverage data is being emitted. */
1143 : :
1144 : : static bool
1145 : 225017 : coverage_obj_init (void)
1146 : : {
1147 : 225017 : tree gcov_info_type;
1148 : 225017 : unsigned n_counters = 0;
1149 : 225017 : unsigned ix;
1150 : 225017 : struct coverage_data *fn;
1151 : 225017 : struct coverage_data **fn_prev;
1152 : 225017 : char name_buf[32];
1153 : :
1154 : 225017 : no_coverage = 1; /* Disable any further coverage. */
1155 : :
1156 : 225017 : if (!prg_ctr_mask)
1157 : : return false;
1158 : :
1159 : 400 : if (symtab->dump_file)
1160 : 3 : fprintf (symtab->dump_file, "Using data file %s\n", da_file_name);
1161 : :
1162 : : /* Prune functions. */
1163 : 2086 : for (fn_prev = &functions_head; (fn = *fn_prev);)
1164 : 1686 : if (DECL_STRUCT_FUNCTION (fn->fn_decl))
1165 : 1686 : fn_prev = &fn->next;
1166 : : else
1167 : : /* The function is not being emitted, remove from list. */
1168 : 0 : *fn_prev = fn->next;
1169 : :
1170 : 400 : if (functions_head == NULL)
1171 : : return false;
1172 : :
1173 : 4000 : for (ix = 0; ix != GCOV_COUNTERS; ix++)
1174 : 3600 : if ((1u << ix) & prg_ctr_mask)
1175 : 711 : n_counters++;
1176 : :
1177 : : /* Build the info and fn_info types. These are mutually recursive. */
1178 : 400 : gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1179 : 400 : gcov_fn_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1180 : 400 : build_fn_info_type (gcov_fn_info_type, n_counters, gcov_info_type);
1181 : 400 : gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1182 : 800 : gcov_fn_info_ptr_type = build_pointer_type
1183 : 400 : (build_qualified_type (gcov_fn_info_type, TYPE_QUAL_CONST));
1184 : 400 : build_info_type (gcov_info_type, gcov_fn_info_ptr_type);
1185 : :
1186 : : /* Build the gcov info var, this is referred to in its own
1187 : : initializer. */
1188 : 400 : gcov_info_var = build_decl (BUILTINS_LOCATION,
1189 : : VAR_DECL, NULL_TREE, gcov_info_type);
1190 : 400 : TREE_STATIC (gcov_info_var) = 1;
1191 : 400 : ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
1192 : 400 : DECL_NAME (gcov_info_var) = get_identifier (name_buf);
1193 : :
1194 : 400 : if (profile_info_section)
1195 : 2 : build_gcov_info_var_registration (gcov_info_type);
1196 : : else
1197 : : {
1198 : 398 : build_init_ctor (gcov_info_type);
1199 : 398 : build_gcov_exit_decl ();
1200 : : }
1201 : :
1202 : : return true;
1203 : : }
1204 : :
1205 : : /* Generate the coverage function info for FN and DATA. Append a
1206 : : pointer to that object to CTOR and return the appended CTOR. */
1207 : :
1208 : : static vec<constructor_elt, va_gc> *
1209 : 1686 : coverage_obj_fn (vec<constructor_elt, va_gc> *ctor, tree fn,
1210 : : struct coverage_data const *data)
1211 : : {
1212 : 1686 : tree init = build_fn_info (data, gcov_fn_info_type, gcov_info_var);
1213 : 1686 : tree var = build_var (fn, gcov_fn_info_type, -1);
1214 : :
1215 : 1686 : DECL_INITIAL (var) = init;
1216 : 1686 : varpool_node::finalize_decl (var);
1217 : :
1218 : 1686 : CONSTRUCTOR_APPEND_ELT (ctor, NULL,
1219 : : build1 (ADDR_EXPR, gcov_fn_info_ptr_type, var));
1220 : 1686 : return ctor;
1221 : : }
1222 : :
1223 : : /* Finalize the coverage data. Generates the array of pointers to
1224 : : function objects from CTOR. Generate the gcov_info initializer. */
1225 : :
1226 : : static void
1227 : 400 : coverage_obj_finish (vec<constructor_elt, va_gc> *ctor,
1228 : : unsigned object_checksum)
1229 : : {
1230 : 400 : unsigned n_functions = vec_safe_length (ctor);
1231 : 400 : tree fn_info_ary_type = build_array_type
1232 : 400 : (build_qualified_type (gcov_fn_info_ptr_type, TYPE_QUAL_CONST),
1233 : 400 : build_index_type (size_int (n_functions - 1)));
1234 : 400 : tree fn_info_ary = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE,
1235 : : fn_info_ary_type);
1236 : 400 : char name_buf[32];
1237 : :
1238 : 400 : TREE_STATIC (fn_info_ary) = 1;
1239 : 400 : ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 1);
1240 : 400 : DECL_NAME (fn_info_ary) = get_identifier (name_buf);
1241 : 400 : DECL_INITIAL (fn_info_ary) = build_constructor (fn_info_ary_type, ctor);
1242 : 400 : varpool_node::finalize_decl (fn_info_ary);
1243 : :
1244 : 400 : DECL_INITIAL (gcov_info_var)
1245 : 400 : = build_info (TREE_TYPE (gcov_info_var), fn_info_ary, object_checksum);
1246 : 400 : varpool_node::finalize_decl (gcov_info_var);
1247 : 400 : }
1248 : :
1249 : : /* Perform file-level initialization. Read in data file, generate name
1250 : : of notes file. */
1251 : :
1252 : : void
1253 : 274481 : coverage_init (const char *filename)
1254 : : {
1255 : 274481 : const char *original_filename = filename;
1256 : 274481 : int original_len = strlen (original_filename);
1257 : : #if HAVE_DOS_BASED_FILE_SYSTEM
1258 : : const char *separator = "\\";
1259 : : #else
1260 : 274481 : const char *separator = "/";
1261 : : #endif
1262 : 274481 : int len = strlen (filename);
1263 : 274481 : int prefix_len = 0;
1264 : :
1265 : : /* Since coverage_init is invoked very early, before the pass
1266 : : manager, we need to set up the dumping explicitly. This is
1267 : : similar to the handling in finish_optimization_passes. */
1268 : 274481 : int profile_pass_num =
1269 : 274481 : g->get_passes ()->get_pass_profile ()->static_pass_number;
1270 : 274481 : g->get_dumps ()->dump_start (profile_pass_num, NULL);
1271 : :
1272 : 274481 : if (!IS_ABSOLUTE_PATH (filename))
1273 : : {
1274 : : /* When a profile_data_prefix is provided, then mangle full path
1275 : : of filename in order to prevent file path clashing. */
1276 : 256014 : if (profile_data_prefix)
1277 : : {
1278 : 3 : filename = concat (getpwd (), separator, filename, NULL);
1279 : 3 : if (profile_prefix_path)
1280 : : {
1281 : 0 : if (startswith (filename, profile_prefix_path))
1282 : : {
1283 : 0 : filename += strlen (profile_prefix_path);
1284 : 0 : while (*filename == *separator)
1285 : 0 : filename++;
1286 : : }
1287 : : else
1288 : 0 : warning (0, "filename %qs does not start with profile "
1289 : : "prefix %qs", filename, profile_prefix_path);
1290 : : }
1291 : 3 : filename = mangle_path (filename);
1292 : 3 : len = strlen (filename);
1293 : : }
1294 : : else
1295 : 256011 : profile_data_prefix = getpwd ();
1296 : : }
1297 : :
1298 : 274481 : if (profile_data_prefix)
1299 : 256014 : prefix_len = strlen (profile_data_prefix);
1300 : :
1301 : : /* Name of da file. */
1302 : 274481 : da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX)
1303 : : + prefix_len + 2);
1304 : :
1305 : 274481 : if (profile_data_prefix)
1306 : : {
1307 : 256014 : memcpy (da_file_name, profile_data_prefix, prefix_len);
1308 : 256014 : da_file_name[prefix_len++] = *separator;
1309 : : }
1310 : 274481 : memcpy (da_file_name + prefix_len, filename, len);
1311 : 274481 : strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX);
1312 : :
1313 : 274481 : bbg_file_stamp = local_tick;
1314 : 274481 : if (flag_auto_profile)
1315 : 0 : read_autofdo_file ();
1316 : 274481 : else if (flag_branch_probabilities)
1317 : 168 : read_counts_file ();
1318 : :
1319 : : /* Name of bbg file. */
1320 : 274481 : if (flag_test_coverage && !flag_compare_debug)
1321 : : {
1322 : 156 : if (profile_note_location)
1323 : 0 : bbg_file_name = xstrdup (profile_note_location);
1324 : : else
1325 : : {
1326 : 156 : bbg_file_name = XNEWVEC (char, original_len + strlen (GCOV_NOTE_SUFFIX) + 1);
1327 : 156 : memcpy (bbg_file_name, original_filename, original_len);
1328 : 156 : strcpy (bbg_file_name + original_len, GCOV_NOTE_SUFFIX);
1329 : : }
1330 : :
1331 : 156 : if (!gcov_open (bbg_file_name, -1))
1332 : : {
1333 : 0 : error ("cannot open %s", bbg_file_name);
1334 : 0 : bbg_file_name = NULL;
1335 : : }
1336 : : else
1337 : : {
1338 : 156 : gcov_write_unsigned (GCOV_NOTE_MAGIC);
1339 : 156 : gcov_write_unsigned (GCOV_VERSION);
1340 : 156 : gcov_write_unsigned (bbg_file_stamp);
1341 : : /* Use an arbitrary checksum */
1342 : 156 : gcov_write_unsigned (0);
1343 : 156 : gcov_write_string (getpwd ());
1344 : :
1345 : : /* Do not support has_unexecuted_blocks for Ada. */
1346 : 156 : gcov_write_unsigned (strcmp (lang_hooks.name, "GNU Ada") != 0);
1347 : : }
1348 : : }
1349 : :
1350 : 274481 : g->get_dumps ()->dump_finish (profile_pass_num);
1351 : 274481 : }
1352 : :
1353 : : /* Performs file-level cleanup. Close notes file, generate coverage
1354 : : variables and constructor. */
1355 : :
1356 : : void
1357 : 225017 : coverage_finish (void)
1358 : : {
1359 : 225017 : if (bbg_file_name && gcov_close ())
1360 : 0 : unlink (bbg_file_name);
1361 : :
1362 : 225017 : if (!flag_branch_probabilities && flag_test_coverage
1363 : 156 : && (!local_tick || local_tick == (unsigned)-1))
1364 : : /* Only remove the da file, if we're emitting coverage code and
1365 : : cannot uniquely stamp it. If we can stamp it, libgcov will DTRT. */
1366 : 0 : unlink (da_file_name);
1367 : :
1368 : : /* Global GCDA checksum that aggregates all functions. */
1369 : 225017 : unsigned object_checksum = 0;
1370 : :
1371 : 225017 : if (coverage_obj_init ())
1372 : : {
1373 : 400 : vec<constructor_elt, va_gc> *fn_ctor = NULL;
1374 : 400 : struct coverage_data *fn;
1375 : :
1376 : 2086 : for (fn = functions_head; fn; fn = fn->next)
1377 : : {
1378 : 1686 : fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
1379 : :
1380 : 1686 : object_checksum = crc32_unsigned (object_checksum, fn->ident);
1381 : 1686 : object_checksum = crc32_unsigned (object_checksum,
1382 : : fn->lineno_checksum);
1383 : 1686 : object_checksum = crc32_unsigned (object_checksum, fn->cfg_checksum);
1384 : : }
1385 : 400 : coverage_obj_finish (fn_ctor, object_checksum);
1386 : : }
1387 : :
1388 : 225017 : XDELETEVEC (da_file_name);
1389 : 225017 : da_file_name = NULL;
1390 : 225017 : }
1391 : :
1392 : : #include "gt-coverage.h"
|