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