1132718Skan/* Read and write coverage files, and associated functionality. 2132718Skan Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 3169689Skan 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. 4132718Skan Contributed by James E. Wilson, UC Berkeley/Cygnus Support; 5132718Skan based on some ideas from Dain Samples of UC Berkeley. 6132718Skan Further mangling by Bob Manson, Cygnus Support. 7132718Skan Further mangled by Nathan Sidwell, CodeSourcery 8132718Skan 9132718SkanThis file is part of GCC. 10132718Skan 11132718SkanGCC is free software; you can redistribute it and/or modify it under 12132718Skanthe terms of the GNU General Public License as published by the Free 13132718SkanSoftware Foundation; either version 2, or (at your option) any later 14132718Skanversion. 15132718Skan 16132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 17132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 18132718SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19132718Skanfor more details. 20132718Skan 21132718SkanYou should have received a copy of the GNU General Public License 22132718Skanalong with GCC; see the file COPYING. If not, write to the Free 23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 24169689Skan02110-1301, USA. */ 25132718Skan 26132718Skan 27132718Skan#define GCOV_LINKAGE 28132718Skan 29132718Skan#include "config.h" 30132718Skan#include "system.h" 31132718Skan#include "coretypes.h" 32132718Skan#include "tm.h" 33132718Skan#include "rtl.h" 34132718Skan#include "tree.h" 35132718Skan#include "flags.h" 36132718Skan#include "output.h" 37132718Skan#include "regs.h" 38132718Skan#include "expr.h" 39132718Skan#include "function.h" 40132718Skan#include "toplev.h" 41132718Skan#include "ggc.h" 42132718Skan#include "coverage.h" 43132718Skan#include "langhooks.h" 44132718Skan#include "hashtab.h" 45169689Skan#include "tree-iterator.h" 46169689Skan#include "cgraph.h" 47132718Skan 48132718Skan#include "gcov-io.c" 49132718Skan 50132718Skanstruct function_list 51132718Skan{ 52132718Skan struct function_list *next; /* next function */ 53132718Skan unsigned ident; /* function ident */ 54132718Skan unsigned checksum; /* function checksum */ 55132718Skan unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */ 56132718Skan}; 57132718Skan 58132718Skan/* Counts information for a function. */ 59132718Skantypedef struct counts_entry 60132718Skan{ 61132718Skan /* We hash by */ 62132718Skan unsigned ident; 63132718Skan unsigned ctr; 64132718Skan 65132718Skan /* Store */ 66132718Skan unsigned checksum; 67132718Skan gcov_type *counts; 68132718Skan struct gcov_ctr_summary summary; 69132718Skan 70132718Skan /* Workspace */ 71132718Skan struct counts_entry *chain; 72132718Skan 73132718Skan} counts_entry_t; 74132718Skan 75132718Skanstatic struct function_list *functions_head = 0; 76132718Skanstatic struct function_list **functions_tail = &functions_head; 77132718Skanstatic unsigned no_coverage = 0; 78132718Skan 79132718Skan/* Cumulative counter information for whole program. */ 80132718Skanstatic unsigned prg_ctr_mask; /* Mask of counter types generated. */ 81132718Skanstatic unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated. */ 82132718Skan 83132718Skan/* Counter information for current function. */ 84132718Skanstatic unsigned fn_ctr_mask; /* Mask of counters used. */ 85132718Skanstatic unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */ 86132718Skanstatic unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */ 87132718Skan 88132718Skan/* Name of the output file for coverage output file. */ 89132718Skanstatic char *bbg_file_name; 90132718Skanstatic unsigned bbg_file_opened; 91132718Skanstatic int bbg_function_announced; 92132718Skan 93132718Skan/* Name of the count data file. */ 94132718Skanstatic char *da_file_name; 95132718Skan 96132718Skan/* Hash table of count data. */ 97132718Skanstatic htab_t counts_hash = NULL; 98132718Skan 99169689Skan/* Trees representing the counter table arrays. */ 100169689Skanstatic GTY(()) tree tree_ctr_tables[GCOV_COUNTERS]; 101169689Skan 102169689Skan/* The names of the counter tables. Not used if we're 103169689Skan generating counters at tree level. */ 104132718Skanstatic GTY(()) rtx ctr_labels[GCOV_COUNTERS]; 105132718Skan 106132718Skan/* The names of merge functions for counters. */ 107132718Skanstatic const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS; 108132718Skanstatic const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES; 109132718Skan 110132718Skan/* Forward declarations. */ 111132718Skanstatic hashval_t htab_counts_entry_hash (const void *); 112132718Skanstatic int htab_counts_entry_eq (const void *, const void *); 113132718Skanstatic void htab_counts_entry_del (void *); 114132718Skanstatic void read_counts_file (void); 115132718Skanstatic unsigned compute_checksum (void); 116132718Skanstatic unsigned coverage_checksum_string (unsigned, const char *); 117132718Skanstatic tree build_fn_info_type (unsigned); 118132718Skanstatic tree build_fn_info_value (const struct function_list *, tree); 119132718Skanstatic tree build_ctr_info_type (void); 120132718Skanstatic tree build_ctr_info_value (unsigned, tree); 121132718Skanstatic tree build_gcov_info (void); 122132718Skanstatic void create_coverage (void); 123169689Skan 124169689Skan/* Return the type node for gcov_type. */ 125132718Skan 126169689Skantree 127169689Skanget_gcov_type (void) 128169689Skan{ 129169689Skan return lang_hooks.types.type_for_size (GCOV_TYPE_SIZE, false); 130169689Skan} 131169689Skan 132169689Skan/* Return the type node for gcov_unsigned_t. */ 133169689Skan 134169689Skanstatic tree 135169689Skanget_gcov_unsigned_t (void) 136169689Skan{ 137169689Skan return lang_hooks.types.type_for_size (32, true); 138169689Skan} 139132718Skan 140132718Skanstatic hashval_t 141132718Skanhtab_counts_entry_hash (const void *of) 142132718Skan{ 143132718Skan const counts_entry_t *entry = of; 144132718Skan 145132718Skan return entry->ident * GCOV_COUNTERS + entry->ctr; 146132718Skan} 147132718Skan 148132718Skanstatic int 149132718Skanhtab_counts_entry_eq (const void *of1, const void *of2) 150132718Skan{ 151132718Skan const counts_entry_t *entry1 = of1; 152132718Skan const counts_entry_t *entry2 = of2; 153132718Skan 154132718Skan return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr; 155132718Skan} 156132718Skan 157132718Skanstatic void 158132718Skanhtab_counts_entry_del (void *of) 159132718Skan{ 160132718Skan counts_entry_t *entry = of; 161132718Skan 162132718Skan free (entry->counts); 163132718Skan free (entry); 164132718Skan} 165132718Skan 166132718Skan/* Read in the counts file, if available. */ 167132718Skan 168132718Skanstatic void 169132718Skanread_counts_file (void) 170132718Skan{ 171132718Skan gcov_unsigned_t fn_ident = 0; 172132718Skan gcov_unsigned_t checksum = -1; 173132718Skan counts_entry_t *summaried = NULL; 174132718Skan unsigned seen_summary = 0; 175132718Skan gcov_unsigned_t tag; 176132718Skan int is_error = 0; 177132718Skan 178132718Skan if (!gcov_open (da_file_name, 1)) 179132718Skan return; 180132718Skan 181132718Skan if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) 182132718Skan { 183169689Skan warning (0, "%qs is not a gcov data file", da_file_name); 184132718Skan gcov_close (); 185132718Skan return; 186132718Skan } 187132718Skan else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION) 188132718Skan { 189132718Skan char v[4], e[4]; 190132718Skan 191132718Skan GCOV_UNSIGNED2STRING (v, tag); 192132718Skan GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 193132718Skan 194169689Skan warning (0, "%qs is version %q.*s, expected version %q.*s", 195161651Skan da_file_name, 4, v, 4, e); 196132718Skan gcov_close (); 197132718Skan return; 198132718Skan } 199132718Skan 200132718Skan /* Read and discard the stamp. */ 201132718Skan gcov_read_unsigned (); 202132718Skan 203132718Skan counts_hash = htab_create (10, 204132718Skan htab_counts_entry_hash, htab_counts_entry_eq, 205132718Skan htab_counts_entry_del); 206132718Skan while ((tag = gcov_read_unsigned ())) 207132718Skan { 208132718Skan gcov_unsigned_t length; 209132718Skan gcov_position_t offset; 210132718Skan 211132718Skan length = gcov_read_unsigned (); 212132718Skan offset = gcov_position (); 213132718Skan if (tag == GCOV_TAG_FUNCTION) 214132718Skan { 215132718Skan fn_ident = gcov_read_unsigned (); 216132718Skan checksum = gcov_read_unsigned (); 217132718Skan if (seen_summary) 218132718Skan { 219132718Skan /* We have already seen a summary, this means that this 220132718Skan new function begins a new set of program runs. We 221132718Skan must unlink the summaried chain. */ 222132718Skan counts_entry_t *entry, *chain; 223132718Skan 224132718Skan for (entry = summaried; entry; entry = chain) 225132718Skan { 226132718Skan chain = entry->chain; 227132718Skan entry->chain = NULL; 228132718Skan } 229132718Skan summaried = NULL; 230132718Skan seen_summary = 0; 231132718Skan } 232132718Skan } 233132718Skan else if (tag == GCOV_TAG_PROGRAM_SUMMARY) 234132718Skan { 235132718Skan counts_entry_t *entry; 236132718Skan struct gcov_summary summary; 237132718Skan 238132718Skan gcov_read_summary (&summary); 239132718Skan seen_summary = 1; 240132718Skan for (entry = summaried; entry; entry = entry->chain) 241132718Skan { 242132718Skan struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr]; 243132718Skan 244132718Skan entry->summary.runs += csum->runs; 245132718Skan entry->summary.sum_all += csum->sum_all; 246132718Skan if (entry->summary.run_max < csum->run_max) 247132718Skan entry->summary.run_max = csum->run_max; 248132718Skan entry->summary.sum_max += csum->sum_max; 249132718Skan } 250132718Skan } 251132718Skan else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident) 252132718Skan { 253132718Skan counts_entry_t **slot, *entry, elt; 254132718Skan unsigned n_counts = GCOV_TAG_COUNTER_NUM (length); 255132718Skan unsigned ix; 256132718Skan 257132718Skan elt.ident = fn_ident; 258132718Skan elt.ctr = GCOV_COUNTER_FOR_TAG (tag); 259132718Skan 260132718Skan slot = (counts_entry_t **) htab_find_slot 261132718Skan (counts_hash, &elt, INSERT); 262132718Skan entry = *slot; 263132718Skan if (!entry) 264132718Skan { 265169689Skan *slot = entry = XCNEW (counts_entry_t); 266132718Skan entry->ident = elt.ident; 267132718Skan entry->ctr = elt.ctr; 268132718Skan entry->checksum = checksum; 269132718Skan entry->summary.num = n_counts; 270169689Skan entry->counts = XCNEWVEC (gcov_type, n_counts); 271132718Skan } 272132718Skan else if (entry->checksum != checksum) 273132718Skan { 274169689Skan error ("coverage mismatch for function %u while reading execution counters", 275132718Skan fn_ident); 276132718Skan error ("checksum is %x instead of %x", entry->checksum, checksum); 277132718Skan htab_delete (counts_hash); 278132718Skan break; 279132718Skan } 280132718Skan else if (entry->summary.num != n_counts) 281132718Skan { 282169689Skan error ("coverage mismatch for function %u while reading execution counters", 283132718Skan fn_ident); 284132718Skan error ("number of counters is %d instead of %d", entry->summary.num, n_counts); 285132718Skan htab_delete (counts_hash); 286132718Skan break; 287132718Skan } 288132718Skan else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE) 289132718Skan { 290132718Skan error ("cannot merge separate %s counters for function %u", 291132718Skan ctr_names[elt.ctr], fn_ident); 292132718Skan goto skip_merge; 293132718Skan } 294132718Skan 295132718Skan if (elt.ctr < GCOV_COUNTERS_SUMMABLE 296132718Skan /* This should always be true for a just allocated entry, 297132718Skan and always false for an existing one. Check this way, in 298132718Skan case the gcov file is corrupt. */ 299132718Skan && (!entry->chain || summaried != entry)) 300132718Skan { 301132718Skan entry->chain = summaried; 302132718Skan summaried = entry; 303132718Skan } 304132718Skan for (ix = 0; ix != n_counts; ix++) 305132718Skan entry->counts[ix] += gcov_read_counter (); 306132718Skan skip_merge:; 307132718Skan } 308132718Skan gcov_sync (offset, length); 309132718Skan if ((is_error = gcov_is_error ())) 310169689Skan { 311169689Skan error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted", 312169689Skan da_file_name); 313169689Skan htab_delete (counts_hash); 314169689Skan break; 315169689Skan } 316132718Skan } 317132718Skan 318132718Skan gcov_close (); 319132718Skan} 320132718Skan 321132718Skan/* Returns the counters for a particular tag. */ 322132718Skan 323132718Skangcov_type * 324132718Skanget_coverage_counts (unsigned counter, unsigned expected, 325132718Skan const struct gcov_ctr_summary **summary) 326132718Skan{ 327132718Skan counts_entry_t *entry, elt; 328132718Skan gcov_unsigned_t checksum = -1; 329132718Skan 330132718Skan /* No hash table, no counts. */ 331132718Skan if (!counts_hash) 332132718Skan { 333132718Skan static int warned = 0; 334132718Skan 335132718Skan if (!warned++) 336169689Skan inform ((flag_guess_branch_prob 337169689Skan ? "file %s not found, execution counts estimated" 338169689Skan : "file %s not found, execution counts assumed to be zero"), 339132718Skan da_file_name); 340132718Skan return NULL; 341132718Skan } 342132718Skan 343132718Skan elt.ident = current_function_funcdef_no + 1; 344132718Skan elt.ctr = counter; 345132718Skan entry = htab_find (counts_hash, &elt); 346132718Skan if (!entry) 347132718Skan { 348169689Skan warning (0, "no coverage for function %qs found", IDENTIFIER_POINTER 349132718Skan (DECL_ASSEMBLER_NAME (current_function_decl))); 350132718Skan return 0; 351132718Skan } 352132718Skan 353132718Skan checksum = compute_checksum (); 354132718Skan if (entry->checksum != checksum) 355132718Skan { 356169689Skan error ("coverage mismatch for function %qs while reading counter %qs", 357132718Skan IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)), 358132718Skan ctr_names[counter]); 359132718Skan error ("checksum is %x instead of %x", entry->checksum, checksum); 360132718Skan return 0; 361132718Skan } 362132718Skan else if (entry->summary.num != expected) 363132718Skan { 364169689Skan error ("coverage mismatch for function %qs while reading counter %qs", 365132718Skan IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)), 366132718Skan ctr_names[counter]); 367132718Skan error ("number of counters is %d instead of %d", entry->summary.num, expected); 368132718Skan return 0; 369132718Skan } 370132718Skan 371132718Skan if (summary) 372132718Skan *summary = &entry->summary; 373132718Skan 374132718Skan return entry->counts; 375132718Skan} 376132718Skan 377132718Skan/* Allocate NUM counters of type COUNTER. Returns nonzero if the 378132718Skan allocation succeeded. */ 379132718Skan 380132718Skanint 381132718Skancoverage_counter_alloc (unsigned counter, unsigned num) 382132718Skan{ 383132718Skan if (no_coverage) 384132718Skan return 0; 385132718Skan 386132718Skan if (!num) 387132718Skan return 1; 388132718Skan 389169689Skan if (!tree_ctr_tables[counter]) 390132718Skan { 391169689Skan /* Generate and save a copy of this so it can be shared. Leave 392169689Skan the index type unspecified for now; it will be set after all 393169689Skan functions have been compiled. */ 394132718Skan char buf[20]; 395169689Skan tree gcov_type_node = get_gcov_type (); 396169689Skan tree gcov_type_array_type 397169689Skan = build_array_type (gcov_type_node, NULL_TREE); 398169689Skan tree_ctr_tables[counter] 399169689Skan = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type); 400169689Skan TREE_STATIC (tree_ctr_tables[counter]) = 1; 401132718Skan ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1); 402169689Skan DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf); 403169689Skan DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (gcov_type_node); 404132718Skan } 405132718Skan fn_b_ctrs[counter] = fn_n_ctrs[counter]; 406132718Skan fn_n_ctrs[counter] += num; 407132718Skan fn_ctr_mask |= 1 << counter; 408132718Skan return 1; 409132718Skan} 410132718Skan 411169689Skan/* Generate a tree to access COUNTER NO. */ 412132718Skan 413169689Skantree 414169689Skantree_coverage_counter_ref (unsigned counter, unsigned no) 415132718Skan{ 416169689Skan tree gcov_type_node = get_gcov_type (); 417132718Skan 418169689Skan gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]); 419132718Skan no += prg_n_ctrs[counter] + fn_b_ctrs[counter]; 420132718Skan 421169689Skan /* "no" here is an array index, scaled to bytes later. */ 422169689Skan return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter], 423169689Skan build_int_cst (NULL_TREE, no), NULL, NULL); 424132718Skan} 425132718Skan 426132718Skan/* Generate a checksum for a string. CHKSUM is the current 427132718Skan checksum. */ 428132718Skan 429132718Skanstatic unsigned 430132718Skancoverage_checksum_string (unsigned chksum, const char *string) 431132718Skan{ 432132718Skan char *dup = NULL; 433259405Spfg char *ptr; 434132718Skan 435132718Skan /* Look for everything that looks if it were produced by 436259563Spfg get_file_function_name and zero out the second part 437132718Skan that may result from flag_random_seed. This is not critical 438132718Skan as the checksums are used only for sanity checking. */ 439259405Spfg#define GLOBAL_PREFIX "_GLOBAL__" 440259405Spfg#define TRAILING_N "N_" 441259405Spfg#define ISCAPXDIGIT(a) (((a) >= '0' && (a) <= '9') || ((a) >= 'A' && (a) <= 'F')) 442259405Spfg if ((ptr = strstr (string, GLOBAL_PREFIX))) 443132718Skan { 444259405Spfg /* Skip _GLOBAL__. */ 445259405Spfg ptr += strlen (GLOBAL_PREFIX); 446132718Skan 447259405Spfg /* Skip optional N_ (in case __GLOBAL_N__). */ 448259405Spfg if (!strncmp (ptr, TRAILING_N, strlen (TRAILING_N))) 449259405Spfg ptr += strlen (TRAILING_N); 450259405Spfg /* At this point, ptr should point after "_GLOBAL__N_" or "_GLOBAL__". */ 451169689Skan 452259405Spfg while ((ptr = strchr (ptr, '_')) != NULL) 453259405Spfg { 454259405Spfg int y; 455259405Spfg /* For every "_" in the rest of the string, 456259405Spfg try the follwing pattern matching */ 457259405Spfg 458259405Spfg /* Skip over '_'. */ 459259405Spfg ptr++; 460259405Spfg#define NDIGITS (8) 461259405Spfg /* Try matching the pattern: 462259405Spfg <8-digit hex>_<8-digit hex> 463259405Spfg The second number is randomly generated 464259405Spfg so we want to mask it out before computing the checksum. */ 465259405Spfg for (y = 0; *ptr != 0 && y < NDIGITS; y++, ptr++) 466259405Spfg if (!ISCAPXDIGIT (*ptr)) 467259405Spfg break; 468259405Spfg if (y != NDIGITS || *ptr != '_') 469259405Spfg continue; 470259405Spfg /* Skip over '_' again. */ 471259405Spfg ptr++; 472259405Spfg for (y = 0; *ptr != 0 && y < NDIGITS; y++, ptr++) 473259405Spfg if (!ISCAPXDIGIT (*ptr)) 474259405Spfg break; 475259405Spfg 476259405Spfg if (y == NDIGITS) 477259405Spfg { 478259405Spfg /* We have a match. 479259405Spfg Duplicate the string and mask out 480259405Spfg the second 8-digit number. */ 481259405Spfg dup = xstrdup (string); 482259405Spfg ptr = dup + (ptr - string); 483259405Spfg for(y = -NDIGITS - 1 ; y < 0; y++) 484259405Spfg { 485259405Spfg ptr[y] = '0'; 486259405Spfg } 487259405Spfg ptr = dup; 488259405Spfg break; 489259405Spfg } 490259405Spfg } 491259405Spfg /* "ptr" should be NULL if we couldn't find the match 492259405Spfg (strchr will return NULL if no match is found), 493259405Spfg or it should point to dup which contains the string 494259405Spfg with the random part masked. */ 495132718Skan } 496132718Skan 497259405Spfg chksum = crc32_string (chksum, (ptr) ? ptr : string); 498259405Spfg 499132718Skan if (dup) 500259405Spfg free (dup); 501132718Skan 502132718Skan return chksum; 503132718Skan} 504132718Skan 505132718Skan/* Compute checksum for the current function. We generate a CRC32. */ 506132718Skan 507132718Skanstatic unsigned 508132718Skancompute_checksum (void) 509132718Skan{ 510169689Skan expanded_location xloc 511169689Skan = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); 512169689Skan unsigned chksum = xloc.line; 513132718Skan 514169689Skan chksum = coverage_checksum_string (chksum, xloc.file); 515132718Skan chksum = coverage_checksum_string 516132718Skan (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl))); 517132718Skan 518132718Skan return chksum; 519132718Skan} 520132718Skan 521132718Skan/* Begin output to the graph file for the current function. 522132718Skan Opens the output file, if not already done. Writes the 523132718Skan function header, if not already done. Returns nonzero if data 524132718Skan should be output. */ 525132718Skan 526132718Skanint 527132718Skancoverage_begin_output (void) 528132718Skan{ 529132718Skan if (no_coverage) 530132718Skan return 0; 531132718Skan 532132718Skan if (!bbg_function_announced) 533132718Skan { 534169689Skan expanded_location xloc 535169689Skan = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); 536132718Skan unsigned long offset; 537132718Skan 538132718Skan if (!bbg_file_opened) 539132718Skan { 540132718Skan if (!gcov_open (bbg_file_name, -1)) 541132718Skan error ("cannot open %s", bbg_file_name); 542132718Skan else 543132718Skan { 544132718Skan gcov_write_unsigned (GCOV_NOTE_MAGIC); 545132718Skan gcov_write_unsigned (GCOV_VERSION); 546132718Skan gcov_write_unsigned (local_tick); 547132718Skan } 548132718Skan bbg_file_opened = 1; 549132718Skan } 550132718Skan 551132718Skan /* Announce function */ 552132718Skan offset = gcov_write_tag (GCOV_TAG_FUNCTION); 553132718Skan gcov_write_unsigned (current_function_funcdef_no + 1); 554132718Skan gcov_write_unsigned (compute_checksum ()); 555132718Skan gcov_write_string (IDENTIFIER_POINTER 556132718Skan (DECL_ASSEMBLER_NAME (current_function_decl))); 557169689Skan gcov_write_string (xloc.file); 558169689Skan gcov_write_unsigned (xloc.line); 559132718Skan gcov_write_length (offset); 560132718Skan 561132718Skan bbg_function_announced = 1; 562132718Skan } 563132718Skan return !gcov_is_error (); 564132718Skan} 565132718Skan 566132718Skan/* Finish coverage data for the current function. Verify no output 567132718Skan error has occurred. Save function coverage counts. */ 568132718Skan 569132718Skanvoid 570132718Skancoverage_end_function (void) 571132718Skan{ 572132718Skan unsigned i; 573132718Skan 574132718Skan if (bbg_file_opened > 1 && gcov_is_error ()) 575132718Skan { 576169689Skan warning (0, "error writing %qs", bbg_file_name); 577132718Skan bbg_file_opened = -1; 578132718Skan } 579132718Skan 580132718Skan if (fn_ctr_mask) 581132718Skan { 582132718Skan struct function_list *item; 583132718Skan 584169689Skan item = XNEW (struct function_list); 585132718Skan 586132718Skan *functions_tail = item; 587132718Skan functions_tail = &item->next; 588132718Skan 589132718Skan item->next = 0; 590132718Skan item->ident = current_function_funcdef_no + 1; 591132718Skan item->checksum = compute_checksum (); 592132718Skan for (i = 0; i != GCOV_COUNTERS; i++) 593132718Skan { 594132718Skan item->n_ctrs[i] = fn_n_ctrs[i]; 595132718Skan prg_n_ctrs[i] += fn_n_ctrs[i]; 596132718Skan fn_n_ctrs[i] = fn_b_ctrs[i] = 0; 597132718Skan } 598132718Skan prg_ctr_mask |= fn_ctr_mask; 599132718Skan fn_ctr_mask = 0; 600132718Skan } 601132718Skan bbg_function_announced = 0; 602132718Skan} 603132718Skan 604132718Skan/* Creates the gcov_fn_info RECORD_TYPE. */ 605132718Skan 606132718Skanstatic tree 607132718Skanbuild_fn_info_type (unsigned int counters) 608132718Skan{ 609169689Skan tree type = lang_hooks.types.make_type (RECORD_TYPE); 610132718Skan tree field, fields; 611132718Skan tree array_type; 612132718Skan 613132718Skan /* ident */ 614169689Skan fields = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 615132718Skan 616132718Skan /* checksum */ 617169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 618132718Skan TREE_CHAIN (field) = fields; 619132718Skan fields = field; 620132718Skan 621169689Skan array_type = build_int_cst (NULL_TREE, counters - 1); 622169689Skan array_type = build_index_type (array_type); 623169689Skan array_type = build_array_type (get_gcov_unsigned_t (), array_type); 624132718Skan 625132718Skan /* counters */ 626132718Skan field = build_decl (FIELD_DECL, NULL_TREE, array_type); 627132718Skan TREE_CHAIN (field) = fields; 628132718Skan fields = field; 629132718Skan 630132718Skan finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE); 631132718Skan 632132718Skan return type; 633132718Skan} 634132718Skan 635132718Skan/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is 636132718Skan the function being processed and TYPE is the gcov_fn_info 637132718Skan RECORD_TYPE. */ 638132718Skan 639132718Skanstatic tree 640132718Skanbuild_fn_info_value (const struct function_list *function, tree type) 641132718Skan{ 642132718Skan tree value = NULL_TREE; 643132718Skan tree fields = TYPE_FIELDS (type); 644132718Skan unsigned ix; 645132718Skan tree array_value = NULL_TREE; 646132718Skan 647132718Skan /* ident */ 648169689Skan value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (), 649169689Skan function->ident), value); 650132718Skan fields = TREE_CHAIN (fields); 651132718Skan 652132718Skan /* checksum */ 653169689Skan value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (), 654169689Skan function->checksum), value); 655132718Skan fields = TREE_CHAIN (fields); 656132718Skan 657132718Skan /* counters */ 658132718Skan for (ix = 0; ix != GCOV_COUNTERS; ix++) 659132718Skan if (prg_ctr_mask & (1 << ix)) 660132718Skan { 661169689Skan tree counters = build_int_cstu (get_gcov_unsigned_t (), 662169689Skan function->n_ctrs[ix]); 663132718Skan 664132718Skan array_value = tree_cons (NULL_TREE, counters, array_value); 665132718Skan } 666132718Skan 667169689Skan /* FIXME: use build_constructor directly. */ 668169689Skan array_value = build_constructor_from_list (TREE_TYPE (fields), 669169689Skan nreverse (array_value)); 670132718Skan value = tree_cons (fields, array_value, value); 671132718Skan 672169689Skan /* FIXME: use build_constructor directly. */ 673169689Skan value = build_constructor_from_list (type, nreverse (value)); 674132718Skan 675132718Skan return value; 676132718Skan} 677132718Skan 678132718Skan/* Creates the gcov_ctr_info RECORD_TYPE. */ 679132718Skan 680132718Skanstatic tree 681132718Skanbuild_ctr_info_type (void) 682132718Skan{ 683169689Skan tree type = lang_hooks.types.make_type (RECORD_TYPE); 684132718Skan tree field, fields = NULL_TREE; 685169689Skan tree gcov_ptr_type = build_pointer_type (get_gcov_type ()); 686132718Skan tree gcov_merge_fn_type; 687132718Skan 688132718Skan /* counters */ 689169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 690132718Skan TREE_CHAIN (field) = fields; 691132718Skan fields = field; 692132718Skan 693132718Skan /* values */ 694132718Skan field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type); 695132718Skan TREE_CHAIN (field) = fields; 696132718Skan fields = field; 697132718Skan 698132718Skan /* merge */ 699132718Skan gcov_merge_fn_type = 700132718Skan build_function_type_list (void_type_node, 701169689Skan gcov_ptr_type, get_gcov_unsigned_t (), 702132718Skan NULL_TREE); 703132718Skan field = build_decl (FIELD_DECL, NULL_TREE, 704132718Skan build_pointer_type (gcov_merge_fn_type)); 705132718Skan TREE_CHAIN (field) = fields; 706132718Skan fields = field; 707132718Skan 708132718Skan finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE); 709132718Skan 710132718Skan return type; 711132718Skan} 712132718Skan 713132718Skan/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is 714132718Skan the counter being processed and TYPE is the gcov_ctr_info 715132718Skan RECORD_TYPE. */ 716132718Skan 717132718Skanstatic tree 718132718Skanbuild_ctr_info_value (unsigned int counter, tree type) 719132718Skan{ 720132718Skan tree value = NULL_TREE; 721132718Skan tree fields = TYPE_FIELDS (type); 722132718Skan tree fn; 723132718Skan 724132718Skan /* counters */ 725132718Skan value = tree_cons (fields, 726169689Skan build_int_cstu (get_gcov_unsigned_t (), 727169689Skan prg_n_ctrs[counter]), 728132718Skan value); 729132718Skan fields = TREE_CHAIN (fields); 730132718Skan 731132718Skan if (prg_n_ctrs[counter]) 732132718Skan { 733169689Skan tree array_type; 734132718Skan 735169689Skan array_type = build_int_cstu (get_gcov_unsigned_t (), 736169689Skan prg_n_ctrs[counter] - 1); 737169689Skan array_type = build_index_type (array_type); 738132718Skan array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)), 739132718Skan array_type); 740132718Skan 741169689Skan TREE_TYPE (tree_ctr_tables[counter]) = array_type; 742169689Skan DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type); 743169689Skan DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type); 744169689Skan assemble_variable (tree_ctr_tables[counter], 0, 0, 0); 745132718Skan 746132718Skan value = tree_cons (fields, 747169689Skan build1 (ADDR_EXPR, TREE_TYPE (fields), 748169689Skan tree_ctr_tables[counter]), 749132718Skan value); 750132718Skan } 751132718Skan else 752132718Skan value = tree_cons (fields, null_pointer_node, value); 753132718Skan fields = TREE_CHAIN (fields); 754132718Skan 755132718Skan fn = build_decl (FUNCTION_DECL, 756132718Skan get_identifier (ctr_merge_functions[counter]), 757132718Skan TREE_TYPE (TREE_TYPE (fields))); 758132718Skan DECL_EXTERNAL (fn) = 1; 759132718Skan TREE_PUBLIC (fn) = 1; 760132718Skan DECL_ARTIFICIAL (fn) = 1; 761132718Skan TREE_NOTHROW (fn) = 1; 762132718Skan value = tree_cons (fields, 763132718Skan build1 (ADDR_EXPR, TREE_TYPE (fields), fn), 764132718Skan value); 765132718Skan 766169689Skan /* FIXME: use build_constructor directly. */ 767169689Skan value = build_constructor_from_list (type, nreverse (value)); 768132718Skan 769132718Skan return value; 770132718Skan} 771132718Skan 772132718Skan/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a 773132718Skan CONSTRUCTOR. */ 774132718Skan 775132718Skanstatic tree 776132718Skanbuild_gcov_info (void) 777132718Skan{ 778132718Skan unsigned n_ctr_types, ix; 779132718Skan tree type, const_type; 780132718Skan tree fn_info_type, fn_info_value = NULL_TREE; 781132718Skan tree fn_info_ptr_type; 782132718Skan tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE; 783132718Skan tree field, fields = NULL_TREE; 784132718Skan tree value = NULL_TREE; 785132718Skan tree filename_string; 786132718Skan char *filename; 787132718Skan int filename_len; 788132718Skan unsigned n_fns; 789132718Skan const struct function_list *fn; 790132718Skan tree string_type; 791132718Skan 792132718Skan /* Count the number of active counters. */ 793132718Skan for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++) 794132718Skan if (prg_ctr_mask & (1 << ix)) 795132718Skan n_ctr_types++; 796132718Skan 797169689Skan type = lang_hooks.types.make_type (RECORD_TYPE); 798132718Skan const_type = build_qualified_type (type, TYPE_QUAL_CONST); 799132718Skan 800132718Skan /* Version ident */ 801169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 802132718Skan TREE_CHAIN (field) = fields; 803132718Skan fields = field; 804169689Skan value = tree_cons (field, build_int_cstu (TREE_TYPE (field), GCOV_VERSION), 805132718Skan value); 806132718Skan 807132718Skan /* next -- NULL */ 808132718Skan field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type)); 809132718Skan TREE_CHAIN (field) = fields; 810132718Skan fields = field; 811132718Skan value = tree_cons (field, null_pointer_node, value); 812132718Skan 813132718Skan /* stamp */ 814169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 815132718Skan TREE_CHAIN (field) = fields; 816132718Skan fields = field; 817169689Skan value = tree_cons (field, build_int_cstu (TREE_TYPE (field), local_tick), 818132718Skan value); 819132718Skan 820132718Skan /* Filename */ 821132718Skan string_type = build_pointer_type (build_qualified_type (char_type_node, 822132718Skan TYPE_QUAL_CONST)); 823132718Skan field = build_decl (FIELD_DECL, NULL_TREE, string_type); 824132718Skan TREE_CHAIN (field) = fields; 825132718Skan fields = field; 826132718Skan filename = getpwd (); 827132718Skan filename = (filename && da_file_name[0] != '/' 828132718Skan ? concat (filename, "/", da_file_name, NULL) 829132718Skan : da_file_name); 830132718Skan filename_len = strlen (filename); 831132718Skan filename_string = build_string (filename_len + 1, filename); 832132718Skan if (filename != da_file_name) 833132718Skan free (filename); 834169689Skan TREE_TYPE (filename_string) = build_array_type 835169689Skan (char_type_node, build_index_type 836169689Skan (build_int_cst (NULL_TREE, filename_len))); 837132718Skan value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string), 838132718Skan value); 839132718Skan 840132718Skan /* Build the fn_info type and initializer. */ 841132718Skan fn_info_type = build_fn_info_type (n_ctr_types); 842132718Skan fn_info_ptr_type = build_pointer_type (build_qualified_type 843132718Skan (fn_info_type, TYPE_QUAL_CONST)); 844132718Skan for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++) 845132718Skan fn_info_value = tree_cons (NULL_TREE, 846132718Skan build_fn_info_value (fn, fn_info_type), 847132718Skan fn_info_value); 848132718Skan if (n_fns) 849132718Skan { 850132718Skan tree array_type; 851132718Skan 852169689Skan array_type = build_index_type (build_int_cst (NULL_TREE, n_fns - 1)); 853132718Skan array_type = build_array_type (fn_info_type, array_type); 854132718Skan 855169689Skan /* FIXME: use build_constructor directly. */ 856169689Skan fn_info_value = build_constructor_from_list (array_type, 857169689Skan nreverse (fn_info_value)); 858132718Skan fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value); 859132718Skan } 860132718Skan else 861132718Skan fn_info_value = null_pointer_node; 862132718Skan 863132718Skan /* number of functions */ 864169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 865132718Skan TREE_CHAIN (field) = fields; 866132718Skan fields = field; 867132718Skan value = tree_cons (field, 868169689Skan build_int_cstu (get_gcov_unsigned_t (), n_fns), 869132718Skan value); 870132718Skan 871132718Skan /* fn_info table */ 872132718Skan field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type); 873132718Skan TREE_CHAIN (field) = fields; 874132718Skan fields = field; 875132718Skan value = tree_cons (field, fn_info_value, value); 876132718Skan 877132718Skan /* counter_mask */ 878169689Skan field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); 879132718Skan TREE_CHAIN (field) = fields; 880132718Skan fields = field; 881132718Skan value = tree_cons (field, 882169689Skan build_int_cstu (get_gcov_unsigned_t (), prg_ctr_mask), 883132718Skan value); 884132718Skan 885132718Skan /* counters */ 886132718Skan ctr_info_type = build_ctr_info_type (); 887169689Skan ctr_info_ary_type = build_index_type (build_int_cst (NULL_TREE, 888169689Skan n_ctr_types)); 889132718Skan ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type); 890132718Skan for (ix = 0; ix != GCOV_COUNTERS; ix++) 891132718Skan if (prg_ctr_mask & (1 << ix)) 892132718Skan ctr_info_value = tree_cons (NULL_TREE, 893132718Skan build_ctr_info_value (ix, ctr_info_type), 894132718Skan ctr_info_value); 895169689Skan /* FIXME: use build_constructor directly. */ 896169689Skan ctr_info_value = build_constructor_from_list (ctr_info_ary_type, 897169689Skan nreverse (ctr_info_value)); 898132718Skan 899132718Skan field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type); 900132718Skan TREE_CHAIN (field) = fields; 901132718Skan fields = field; 902132718Skan value = tree_cons (field, ctr_info_value, value); 903132718Skan 904132718Skan finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE); 905132718Skan 906169689Skan /* FIXME: use build_constructor directly. */ 907169689Skan value = build_constructor_from_list (type, nreverse (value)); 908132718Skan 909132718Skan return value; 910132718Skan} 911132718Skan 912132718Skan/* Write out the structure which libgcov uses to locate all the 913132718Skan counters. The structures used here must match those defined in 914132718Skan gcov-io.h. Write out the constructor to call __gcov_init. */ 915132718Skan 916132718Skanstatic void 917132718Skancreate_coverage (void) 918132718Skan{ 919169689Skan tree gcov_info, gcov_init, body, t; 920169689Skan char name_buf[32]; 921132718Skan 922132718Skan no_coverage = 1; /* Disable any further coverage. */ 923132718Skan 924132718Skan if (!prg_ctr_mask) 925132718Skan return; 926132718Skan 927169689Skan t = build_gcov_info (); 928132718Skan 929169689Skan gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t)); 930132718Skan TREE_STATIC (gcov_info) = 1; 931169689Skan ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0); 932169689Skan DECL_NAME (gcov_info) = get_identifier (name_buf); 933169689Skan DECL_INITIAL (gcov_info) = t; 934132718Skan 935132718Skan /* Build structure. */ 936132718Skan assemble_variable (gcov_info, 0, 0, 0); 937132718Skan 938169689Skan /* Build a decl for __gcov_init. */ 939169689Skan t = build_pointer_type (TREE_TYPE (gcov_info)); 940169689Skan t = build_function_type_list (void_type_node, t, NULL); 941169689Skan t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t); 942169689Skan TREE_PUBLIC (t) = 1; 943169689Skan DECL_EXTERNAL (t) = 1; 944169689Skan gcov_init = t; 945132718Skan 946169689Skan /* Generate a call to __gcov_init(&gcov_info). */ 947169689Skan body = NULL; 948169689Skan t = build_fold_addr_expr (gcov_info); 949169689Skan t = tree_cons (NULL, t, NULL); 950169689Skan t = build_function_call_expr (gcov_init, t); 951169689Skan append_to_statement_list (t, &body); 952132718Skan 953169689Skan /* Generate a constructor to run it. */ 954169689Skan cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY); 955132718Skan} 956132718Skan 957132718Skan/* Perform file-level initialization. Read in data file, generate name 958132718Skan of graph file. */ 959132718Skan 960132718Skanvoid 961132718Skancoverage_init (const char *filename) 962132718Skan{ 963132718Skan int len = strlen (filename); 964132718Skan 965132718Skan /* Name of da file. */ 966169689Skan da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) + 1); 967132718Skan strcpy (da_file_name, filename); 968132718Skan strcat (da_file_name, GCOV_DATA_SUFFIX); 969132718Skan 970132718Skan /* Name of bbg file. */ 971169689Skan bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1); 972132718Skan strcpy (bbg_file_name, filename); 973132718Skan strcat (bbg_file_name, GCOV_NOTE_SUFFIX); 974132718Skan 975132718Skan read_counts_file (); 976132718Skan} 977132718Skan 978132718Skan/* Performs file-level cleanup. Close graph file, generate coverage 979132718Skan variables and constructor. */ 980132718Skan 981132718Skanvoid 982132718Skancoverage_finish (void) 983132718Skan{ 984132718Skan create_coverage (); 985132718Skan if (bbg_file_opened) 986132718Skan { 987132718Skan int error = gcov_close (); 988132718Skan 989132718Skan if (error) 990132718Skan unlink (bbg_file_name); 991132718Skan if (!local_tick) 992132718Skan /* Only remove the da file, if we cannot stamp it. If we can 993132718Skan stamp it, libgcov will DTRT. */ 994132718Skan unlink (da_file_name); 995132718Skan } 996132718Skan} 997132718Skan 998132718Skan#include "gt-coverage.h" 999