1132718Skan/* Routines required for instrumenting a program. */ 2132718Skan/* Compile this one with gcc. */ 3132718Skan/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 4169689Skan 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 5132718Skan 6132718SkanThis file is part of GCC. 7132718Skan 8132718SkanGCC is free software; you can redistribute it and/or modify it under 9132718Skanthe terms of the GNU General Public License as published by the Free 10132718SkanSoftware Foundation; either version 2, or (at your option) any later 11132718Skanversion. 12132718Skan 13132718SkanIn addition to the permissions in the GNU General Public License, the 14132718SkanFree Software Foundation gives you unlimited permission to link the 15132718Skancompiled version of this file into combinations with other programs, 16132718Skanand to distribute those combinations without any restriction coming 17132718Skanfrom the use of this file. (The General Public License restrictions 18132718Skando apply in other respects; for example, they cover modification of 19132718Skanthe file, and distribution when not linked into a combine 20132718Skanexecutable.) 21132718Skan 22132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 23132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 24132718SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25132718Skanfor more details. 26132718Skan 27132718SkanYou should have received a copy of the GNU General Public License 28132718Skanalong with GCC; see the file COPYING. If not, write to the Free 29169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 30169689Skan02110-1301, USA. */ 31132718Skan 32132718Skan#include "tconfig.h" 33132718Skan#include "tsystem.h" 34132718Skan#include "coretypes.h" 35132718Skan#include "tm.h" 36132718Skan 37132718Skan#if defined(inhibit_libc) 38132718Skan#define IN_LIBGCOV (-1) 39132718Skan#else 40132718Skan#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ 41132718Skan#include <stdio.h> 42132718Skan#define IN_LIBGCOV 1 43132718Skan#if defined(L_gcov) 44132718Skan#define GCOV_LINKAGE /* nothing */ 45132718Skan#endif 46132718Skan#endif 47132718Skan#include "gcov-io.h" 48132718Skan 49132718Skan#if defined(inhibit_libc) 50132718Skan/* If libc and its header files are not available, provide dummy functions. */ 51132718Skan 52132718Skan#ifdef L_gcov 53132718Skanvoid __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} 54132718Skanvoid __gcov_flush (void) {} 55132718Skan#endif 56132718Skan 57132718Skan#ifdef L_gcov_merge_add 58132718Skanvoid __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), 59132718Skan unsigned n_counters __attribute__ ((unused))) {} 60132718Skan#endif 61132718Skan 62132718Skan#ifdef L_gcov_merge_single 63132718Skanvoid __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), 64132718Skan unsigned n_counters __attribute__ ((unused))) {} 65132718Skan#endif 66132718Skan 67132718Skan#ifdef L_gcov_merge_delta 68132718Skanvoid __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)), 69132718Skan unsigned n_counters __attribute__ ((unused))) {} 70132718Skan#endif 71132718Skan 72132718Skan#else 73132718Skan 74132718Skan#include <string.h> 75132718Skan#if GCOV_LOCKED 76132718Skan#include <fcntl.h> 77132718Skan#include <errno.h> 78132718Skan#include <sys/stat.h> 79132718Skan#endif 80132718Skan 81132718Skan#ifdef L_gcov 82132718Skan#include "gcov-io.c" 83132718Skan 84132718Skan/* Chain of per-object gcov structures. */ 85132718Skanstatic struct gcov_info *gcov_list; 86132718Skan 87132718Skan/* A program checksum allows us to distinguish program data for an 88132718Skan object file included in multiple programs. */ 89132718Skanstatic gcov_unsigned_t gcov_crc32; 90132718Skan 91169689Skan/* Size of the longest file name. */ 92169689Skanstatic size_t gcov_max_filename = 0; 93169689Skan 94169689Skan#ifdef TARGET_POSIX_IO 95169689Skan/* Make sure path component of the given FILENAME exists, create 96169689Skan missing directories. FILENAME must be writable. 97169689Skan Returns zero on success, or -1 if an error occurred. */ 98169689Skan 99132718Skanstatic int 100169689Skancreate_file_directory (char *filename) 101132718Skan{ 102169689Skan char *s; 103169689Skan 104169689Skan for (s = filename + 1; *s != '\0'; s++) 105169689Skan if (IS_DIR_SEPARATOR(*s)) 106169689Skan { 107169689Skan char sep = *s; 108169689Skan *s = '\0'; 109169689Skan 110169689Skan /* Try to make directory if it doesn't already exist. */ 111169689Skan if (access (filename, F_OK) == -1 112169689Skan && mkdir (filename, 0755) == -1 113169689Skan /* The directory might have been made by another process. */ 114169689Skan && errno != EEXIST) 115169689Skan { 116169689Skan fprintf (stderr, "profiling:%s:Cannot create directory\n", 117169689Skan filename); 118169689Skan *s = sep; 119169689Skan return -1; 120169689Skan }; 121169689Skan 122169689Skan *s = sep; 123169689Skan }; 124169689Skan return 0; 125169689Skan} 126169689Skan#endif 127169689Skan 128169689Skan/* Check if VERSION of the info block PTR matches libgcov one. 129169689Skan Return 1 on success, or zero in case of versions mismatch. 130169689Skan If FILENAME is not NULL, its value used for reporting purposes 131169689Skan instead of value from the info block. */ 132169689Skan 133169689Skanstatic int 134169689Skangcov_version (struct gcov_info *ptr, gcov_unsigned_t version, 135169689Skan const char *filename) 136169689Skan{ 137132718Skan if (version != GCOV_VERSION) 138132718Skan { 139132718Skan char v[4], e[4]; 140132718Skan 141132718Skan GCOV_UNSIGNED2STRING (v, version); 142132718Skan GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 143132718Skan 144132718Skan fprintf (stderr, 145132718Skan "profiling:%s:Version mismatch - expected %.4s got %.4s\n", 146169689Skan filename? filename : ptr->filename, e, v); 147132718Skan return 0; 148132718Skan } 149132718Skan return 1; 150132718Skan} 151132718Skan 152132718Skan/* Dump the coverage counts. We merge with existing counts when 153132718Skan possible, to avoid growing the .da files ad infinitum. We use this 154132718Skan program's checksum to make sure we only accumulate whole program 155132718Skan statistics to the correct summary. An object file might be embedded 156132718Skan in two separate programs, and we must keep the two program 157132718Skan summaries separate. */ 158132718Skan 159132718Skanstatic void 160132718Skangcov_exit (void) 161132718Skan{ 162132718Skan struct gcov_info *gi_ptr; 163132718Skan struct gcov_summary this_program; 164132718Skan struct gcov_summary all; 165132718Skan struct gcov_ctr_summary *cs_ptr; 166132718Skan const struct gcov_ctr_info *ci_ptr; 167132718Skan unsigned t_ix; 168132718Skan gcov_unsigned_t c_num; 169169689Skan const char *gcov_prefix; 170169689Skan int gcov_prefix_strip = 0; 171169689Skan size_t prefix_length; 172169689Skan char *gi_filename, *gi_filename_up; 173132718Skan 174132718Skan memset (&all, 0, sizeof (all)); 175132718Skan /* Find the totals for this execution. */ 176132718Skan memset (&this_program, 0, sizeof (this_program)); 177132718Skan for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 178132718Skan { 179132718Skan ci_ptr = gi_ptr->counts; 180132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 181132718Skan { 182132718Skan if (!((1 << t_ix) & gi_ptr->ctr_mask)) 183132718Skan continue; 184132718Skan 185132718Skan cs_ptr = &this_program.ctrs[t_ix]; 186132718Skan cs_ptr->num += ci_ptr->num; 187132718Skan for (c_num = 0; c_num < ci_ptr->num; c_num++) 188132718Skan { 189132718Skan cs_ptr->sum_all += ci_ptr->values[c_num]; 190132718Skan if (cs_ptr->run_max < ci_ptr->values[c_num]) 191132718Skan cs_ptr->run_max = ci_ptr->values[c_num]; 192132718Skan } 193132718Skan ci_ptr++; 194132718Skan } 195132718Skan } 196132718Skan 197169689Skan /* Get file name relocation prefix. Non-absolute values are ignored. */ 198169689Skan gcov_prefix = getenv("GCOV_PREFIX"); 199169689Skan if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix)) 200169689Skan { 201169689Skan /* Check if the level of dirs to strip off specified. */ 202169689Skan char *tmp = getenv("GCOV_PREFIX_STRIP"); 203169689Skan if (tmp) 204169689Skan { 205169689Skan gcov_prefix_strip = atoi (tmp); 206169689Skan /* Do not consider negative values. */ 207169689Skan if (gcov_prefix_strip < 0) 208169689Skan gcov_prefix_strip = 0; 209169689Skan } 210169689Skan 211169689Skan prefix_length = strlen(gcov_prefix); 212169689Skan 213169689Skan /* Remove an unnecessary trailing '/' */ 214169689Skan if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1])) 215169689Skan prefix_length--; 216169689Skan } 217169689Skan else 218169689Skan prefix_length = 0; 219169689Skan 220169689Skan /* Allocate and initialize the filename scratch space. */ 221169689Skan gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1); 222169689Skan if (prefix_length) 223169689Skan memcpy (gi_filename, gcov_prefix, prefix_length); 224169689Skan gi_filename_up = gi_filename + prefix_length; 225169689Skan 226132718Skan /* Now merge each file. */ 227132718Skan for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 228132718Skan { 229132718Skan struct gcov_summary this_object; 230132718Skan struct gcov_summary object, program; 231132718Skan gcov_type *values[GCOV_COUNTERS]; 232132718Skan const struct gcov_fn_info *fi_ptr; 233132718Skan unsigned fi_stride; 234132718Skan unsigned c_ix, f_ix, n_counts; 235132718Skan struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; 236132718Skan int error = 0; 237132718Skan gcov_unsigned_t tag, length; 238132718Skan gcov_position_t summary_pos = 0; 239169689Skan gcov_position_t eof_pos = 0; 240132718Skan 241132718Skan memset (&this_object, 0, sizeof (this_object)); 242132718Skan memset (&object, 0, sizeof (object)); 243132718Skan 244169689Skan /* Build relocated filename, stripping off leading 245169689Skan directories from the initial filename if requested. */ 246169689Skan if (gcov_prefix_strip > 0) 247169689Skan { 248169689Skan int level = 0; 249169689Skan const char *fname = gi_ptr->filename; 250169689Skan const char *s; 251169689Skan 252169689Skan /* Skip selected directory levels. */ 253169689Skan for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++) 254169689Skan if (IS_DIR_SEPARATOR(*s)) 255169689Skan { 256169689Skan fname = s; 257169689Skan level++; 258169689Skan }; 259169689Skan 260169689Skan /* Update complete filename with stripped original. */ 261169689Skan strcpy (gi_filename_up, fname); 262169689Skan } 263169689Skan else 264169689Skan strcpy (gi_filename_up, gi_ptr->filename); 265169689Skan 266132718Skan /* Totals for this object file. */ 267132718Skan ci_ptr = gi_ptr->counts; 268132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 269132718Skan { 270132718Skan if (!((1 << t_ix) & gi_ptr->ctr_mask)) 271132718Skan continue; 272132718Skan 273132718Skan cs_ptr = &this_object.ctrs[t_ix]; 274132718Skan cs_ptr->num += ci_ptr->num; 275132718Skan for (c_num = 0; c_num < ci_ptr->num; c_num++) 276132718Skan { 277132718Skan cs_ptr->sum_all += ci_ptr->values[c_num]; 278132718Skan if (cs_ptr->run_max < ci_ptr->values[c_num]) 279132718Skan cs_ptr->run_max = ci_ptr->values[c_num]; 280132718Skan } 281132718Skan 282132718Skan ci_ptr++; 283132718Skan } 284132718Skan 285132718Skan c_ix = 0; 286132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 287132718Skan if ((1 << t_ix) & gi_ptr->ctr_mask) 288132718Skan { 289132718Skan values[c_ix] = gi_ptr->counts[c_ix].values; 290132718Skan c_ix++; 291132718Skan } 292132718Skan 293132718Skan /* Calculate the function_info stride. This depends on the 294132718Skan number of counter types being measured. */ 295132718Skan fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned); 296132718Skan if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) 297132718Skan { 298132718Skan fi_stride += __alignof__ (struct gcov_fn_info) - 1; 299132718Skan fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); 300132718Skan } 301132718Skan 302169689Skan if (!gcov_open (gi_filename)) 303132718Skan { 304169689Skan#ifdef TARGET_POSIX_IO 305169689Skan /* Open failed likely due to missed directory. 306169689Skan Create directory and retry to open file. */ 307169689Skan if (create_file_directory (gi_filename)) 308169689Skan { 309169689Skan fprintf (stderr, "profiling:%s:Skip\n", gi_filename); 310169689Skan continue; 311169689Skan } 312169689Skan#endif 313169689Skan if (!gcov_open (gi_filename)) 314169689Skan { 315169689Skan fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename); 316169689Skan continue; 317169689Skan } 318132718Skan } 319132718Skan 320132718Skan tag = gcov_read_unsigned (); 321132718Skan if (tag) 322132718Skan { 323132718Skan /* Merge data from file. */ 324132718Skan if (tag != GCOV_DATA_MAGIC) 325132718Skan { 326132718Skan fprintf (stderr, "profiling:%s:Not a gcov data file\n", 327169689Skan gi_filename); 328169689Skan goto read_fatal; 329132718Skan } 330132718Skan length = gcov_read_unsigned (); 331169689Skan if (!gcov_version (gi_ptr, length, gi_filename)) 332132718Skan goto read_fatal; 333132718Skan 334132718Skan length = gcov_read_unsigned (); 335132718Skan if (length != gi_ptr->stamp) 336169689Skan /* Read from a different compilation. Overwrite the file. */ 337169689Skan goto rewrite; 338132718Skan 339132718Skan /* Merge execution counts for each function. */ 340132718Skan for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 341132718Skan { 342132718Skan fi_ptr = (const struct gcov_fn_info *) 343132718Skan ((const char *) gi_ptr->functions + f_ix * fi_stride); 344132718Skan tag = gcov_read_unsigned (); 345132718Skan length = gcov_read_unsigned (); 346132718Skan 347132718Skan /* Check function. */ 348132718Skan if (tag != GCOV_TAG_FUNCTION 349132718Skan || length != GCOV_TAG_FUNCTION_LENGTH 350132718Skan || gcov_read_unsigned () != fi_ptr->ident 351132718Skan || gcov_read_unsigned () != fi_ptr->checksum) 352132718Skan { 353132718Skan read_mismatch:; 354132718Skan fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", 355169689Skan gi_filename, 356132718Skan f_ix + 1 ? "function" : "summaries"); 357132718Skan goto read_fatal; 358132718Skan } 359132718Skan 360132718Skan c_ix = 0; 361132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 362132718Skan { 363132718Skan gcov_merge_fn merge; 364132718Skan 365132718Skan if (!((1 << t_ix) & gi_ptr->ctr_mask)) 366132718Skan continue; 367132718Skan 368132718Skan n_counts = fi_ptr->n_ctrs[c_ix]; 369132718Skan merge = gi_ptr->counts[c_ix].merge; 370132718Skan 371132718Skan tag = gcov_read_unsigned (); 372132718Skan length = gcov_read_unsigned (); 373132718Skan if (tag != GCOV_TAG_FOR_COUNTER (t_ix) 374132718Skan || length != GCOV_TAG_COUNTER_LENGTH (n_counts)) 375132718Skan goto read_mismatch; 376132718Skan (*merge) (values[c_ix], n_counts); 377132718Skan values[c_ix] += n_counts; 378132718Skan c_ix++; 379132718Skan } 380132718Skan if ((error = gcov_is_error ())) 381132718Skan goto read_error; 382132718Skan } 383132718Skan 384132718Skan f_ix = ~0u; 385132718Skan /* Check program & object summary */ 386132718Skan while (1) 387132718Skan { 388132718Skan int is_program; 389132718Skan 390169689Skan eof_pos = gcov_position (); 391132718Skan tag = gcov_read_unsigned (); 392132718Skan if (!tag) 393132718Skan break; 394169689Skan 395132718Skan length = gcov_read_unsigned (); 396132718Skan is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; 397132718Skan if (length != GCOV_TAG_SUMMARY_LENGTH 398132718Skan || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY)) 399132718Skan goto read_mismatch; 400132718Skan gcov_read_summary (is_program ? &program : &object); 401132718Skan if ((error = gcov_is_error ())) 402132718Skan goto read_error; 403132718Skan if (is_program && program.checksum == gcov_crc32) 404132718Skan { 405169689Skan summary_pos = eof_pos; 406132718Skan goto rewrite; 407132718Skan } 408132718Skan } 409132718Skan } 410169689Skan goto rewrite; 411132718Skan 412169689Skan read_error:; 413169689Skan fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" 414169689Skan : "profiling:%s:Error merging\n", gi_filename); 415169689Skan 416169689Skan read_fatal:; 417169689Skan gcov_close (); 418169689Skan continue; 419169689Skan 420132718Skan rewrite:; 421132718Skan gcov_rewrite (); 422132718Skan if (!summary_pos) 423132718Skan memset (&program, 0, sizeof (program)); 424132718Skan 425132718Skan /* Merge the summaries. */ 426132718Skan f_ix = ~0u; 427132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 428132718Skan { 429132718Skan cs_obj = &object.ctrs[t_ix]; 430132718Skan cs_tobj = &this_object.ctrs[t_ix]; 431132718Skan cs_prg = &program.ctrs[t_ix]; 432132718Skan cs_tprg = &this_program.ctrs[t_ix]; 433132718Skan cs_all = &all.ctrs[t_ix]; 434132718Skan 435132718Skan if ((1 << t_ix) & gi_ptr->ctr_mask) 436132718Skan { 437132718Skan if (!cs_obj->runs++) 438132718Skan cs_obj->num = cs_tobj->num; 439132718Skan else if (cs_obj->num != cs_tobj->num) 440132718Skan goto read_mismatch; 441132718Skan cs_obj->sum_all += cs_tobj->sum_all; 442132718Skan if (cs_obj->run_max < cs_tobj->run_max) 443132718Skan cs_obj->run_max = cs_tobj->run_max; 444132718Skan cs_obj->sum_max += cs_tobj->run_max; 445132718Skan 446132718Skan if (!cs_prg->runs++) 447132718Skan cs_prg->num = cs_tprg->num; 448132718Skan else if (cs_prg->num != cs_tprg->num) 449132718Skan goto read_mismatch; 450132718Skan cs_prg->sum_all += cs_tprg->sum_all; 451132718Skan if (cs_prg->run_max < cs_tprg->run_max) 452132718Skan cs_prg->run_max = cs_tprg->run_max; 453132718Skan cs_prg->sum_max += cs_tprg->run_max; 454132718Skan } 455132718Skan else if (cs_obj->num || cs_prg->num) 456132718Skan goto read_mismatch; 457132718Skan 458132718Skan if (!cs_all->runs && cs_prg->runs) 459132718Skan memcpy (cs_all, cs_prg, sizeof (*cs_all)); 460132718Skan else if (!all.checksum 461132718Skan && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs) 462132718Skan && memcmp (cs_all, cs_prg, sizeof (*cs_all))) 463132718Skan { 464132718Skan fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", 465169689Skan gi_filename, GCOV_LOCKED 466132718Skan ? "" : " or concurrent update without locking support"); 467132718Skan all.checksum = ~0u; 468132718Skan } 469132718Skan } 470132718Skan 471132718Skan c_ix = 0; 472132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 473132718Skan if ((1 << t_ix) & gi_ptr->ctr_mask) 474132718Skan { 475132718Skan values[c_ix] = gi_ptr->counts[c_ix].values; 476132718Skan c_ix++; 477132718Skan } 478132718Skan 479132718Skan program.checksum = gcov_crc32; 480132718Skan 481132718Skan /* Write out the data. */ 482132718Skan gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); 483132718Skan gcov_write_unsigned (gi_ptr->stamp); 484132718Skan 485132718Skan /* Write execution counts for each function. */ 486132718Skan for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 487132718Skan { 488132718Skan fi_ptr = (const struct gcov_fn_info *) 489132718Skan ((const char *) gi_ptr->functions + f_ix * fi_stride); 490132718Skan 491132718Skan /* Announce function. */ 492132718Skan gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH); 493132718Skan gcov_write_unsigned (fi_ptr->ident); 494132718Skan gcov_write_unsigned (fi_ptr->checksum); 495132718Skan 496132718Skan c_ix = 0; 497132718Skan for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 498132718Skan { 499132718Skan gcov_type *c_ptr; 500132718Skan 501132718Skan if (!((1 << t_ix) & gi_ptr->ctr_mask)) 502132718Skan continue; 503132718Skan 504132718Skan n_counts = fi_ptr->n_ctrs[c_ix]; 505132718Skan 506132718Skan gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), 507132718Skan GCOV_TAG_COUNTER_LENGTH (n_counts)); 508132718Skan c_ptr = values[c_ix]; 509132718Skan while (n_counts--) 510132718Skan gcov_write_counter (*c_ptr++); 511132718Skan 512132718Skan values[c_ix] = c_ptr; 513132718Skan c_ix++; 514132718Skan } 515132718Skan } 516132718Skan 517132718Skan /* Object file summary. */ 518132718Skan gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); 519132718Skan 520132718Skan /* Generate whole program statistics. */ 521169689Skan if (eof_pos) 522169689Skan gcov_seek (eof_pos); 523132718Skan gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program); 524169689Skan if (!summary_pos) 525169689Skan gcov_write_unsigned (0); 526132718Skan if ((error = gcov_close ())) 527132718Skan fprintf (stderr, error < 0 ? 528132718Skan "profiling:%s:Overflow writing\n" : 529132718Skan "profiling:%s:Error writing\n", 530169689Skan gi_filename); 531132718Skan } 532132718Skan} 533132718Skan 534132718Skan/* Add a new object file onto the bb chain. Invoked automatically 535132718Skan when running an object file's global ctors. */ 536132718Skan 537132718Skanvoid 538132718Skan__gcov_init (struct gcov_info *info) 539132718Skan{ 540132718Skan if (!info->version) 541132718Skan return; 542169689Skan if (gcov_version (info, info->version, 0)) 543132718Skan { 544132718Skan const char *ptr = info->filename; 545132718Skan gcov_unsigned_t crc32 = gcov_crc32; 546169689Skan size_t filename_length = strlen(info->filename); 547169689Skan 548169689Skan /* Refresh the longest file name information */ 549169689Skan if (filename_length > gcov_max_filename) 550169689Skan gcov_max_filename = filename_length; 551169689Skan 552132718Skan do 553132718Skan { 554132718Skan unsigned ix; 555132718Skan gcov_unsigned_t value = *ptr << 24; 556132718Skan 557132718Skan for (ix = 8; ix--; value <<= 1) 558132718Skan { 559132718Skan gcov_unsigned_t feedback; 560132718Skan 561132718Skan feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; 562132718Skan crc32 <<= 1; 563132718Skan crc32 ^= feedback; 564132718Skan } 565132718Skan } 566132718Skan while (*ptr++); 567132718Skan 568132718Skan gcov_crc32 = crc32; 569132718Skan 570132718Skan if (!gcov_list) 571132718Skan atexit (gcov_exit); 572132718Skan 573132718Skan info->next = gcov_list; 574132718Skan gcov_list = info; 575132718Skan } 576132718Skan info->version = 0; 577132718Skan} 578132718Skan 579132718Skan/* Called before fork or exec - write out profile information gathered so 580132718Skan far and reset it to zero. This avoids duplication or loss of the 581132718Skan profile information gathered so far. */ 582132718Skan 583132718Skanvoid 584132718Skan__gcov_flush (void) 585132718Skan{ 586132718Skan const struct gcov_info *gi_ptr; 587132718Skan 588132718Skan gcov_exit (); 589132718Skan for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) 590132718Skan { 591132718Skan unsigned t_ix; 592132718Skan const struct gcov_ctr_info *ci_ptr; 593132718Skan 594132718Skan for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++) 595132718Skan if ((1 << t_ix) & gi_ptr->ctr_mask) 596132718Skan { 597132718Skan memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); 598132718Skan ci_ptr++; 599132718Skan } 600132718Skan } 601132718Skan} 602132718Skan 603132718Skan#endif /* L_gcov */ 604132718Skan 605132718Skan#ifdef L_gcov_merge_add 606132718Skan/* The profile merging function that just adds the counters. It is given 607132718Skan an array COUNTERS of N_COUNTERS old counters and it reads the same number 608132718Skan of counters from the gcov file. */ 609132718Skanvoid 610132718Skan__gcov_merge_add (gcov_type *counters, unsigned n_counters) 611132718Skan{ 612132718Skan for (; n_counters; counters++, n_counters--) 613132718Skan *counters += gcov_read_counter (); 614132718Skan} 615132718Skan#endif /* L_gcov_merge_add */ 616132718Skan 617132718Skan#ifdef L_gcov_merge_single 618132718Skan/* The profile merging function for choosing the most common value. 619132718Skan It is given an array COUNTERS of N_COUNTERS old counters and it 620132718Skan reads the same number of counters from the gcov file. The counters 621132718Skan are split into 3-tuples where the members of the tuple have 622132718Skan meanings: 623132718Skan 624132718Skan -- the stored candidate on the most common value of the measured entity 625132718Skan -- counter 626132718Skan -- total number of evaluations of the value */ 627132718Skanvoid 628132718Skan__gcov_merge_single (gcov_type *counters, unsigned n_counters) 629132718Skan{ 630132718Skan unsigned i, n_measures; 631132718Skan gcov_type value, counter, all; 632132718Skan 633169689Skan gcc_assert (!(n_counters % 3)); 634132718Skan n_measures = n_counters / 3; 635132718Skan for (i = 0; i < n_measures; i++, counters += 3) 636132718Skan { 637132718Skan value = gcov_read_counter (); 638132718Skan counter = gcov_read_counter (); 639132718Skan all = gcov_read_counter (); 640132718Skan 641132718Skan if (counters[0] == value) 642132718Skan counters[1] += counter; 643132718Skan else if (counter > counters[1]) 644132718Skan { 645132718Skan counters[0] = value; 646132718Skan counters[1] = counter - counters[1]; 647132718Skan } 648132718Skan else 649132718Skan counters[1] -= counter; 650132718Skan counters[2] += all; 651132718Skan } 652132718Skan} 653132718Skan#endif /* L_gcov_merge_single */ 654132718Skan 655132718Skan#ifdef L_gcov_merge_delta 656132718Skan/* The profile merging function for choosing the most common 657132718Skan difference between two consecutive evaluations of the value. It is 658132718Skan given an array COUNTERS of N_COUNTERS old counters and it reads the 659132718Skan same number of counters from the gcov file. The counters are split 660132718Skan into 4-tuples where the members of the tuple have meanings: 661132718Skan 662132718Skan -- the last value of the measured entity 663132718Skan -- the stored candidate on the most common difference 664132718Skan -- counter 665132718Skan -- total number of evaluations of the value */ 666132718Skanvoid 667132718Skan__gcov_merge_delta (gcov_type *counters, unsigned n_counters) 668132718Skan{ 669132718Skan unsigned i, n_measures; 670132718Skan gcov_type last, value, counter, all; 671132718Skan 672169689Skan gcc_assert (!(n_counters % 4)); 673132718Skan n_measures = n_counters / 4; 674132718Skan for (i = 0; i < n_measures; i++, counters += 4) 675132718Skan { 676132718Skan last = gcov_read_counter (); 677132718Skan value = gcov_read_counter (); 678132718Skan counter = gcov_read_counter (); 679132718Skan all = gcov_read_counter (); 680132718Skan 681132718Skan if (counters[1] == value) 682132718Skan counters[2] += counter; 683132718Skan else if (counter > counters[2]) 684132718Skan { 685132718Skan counters[1] = value; 686132718Skan counters[2] = counter - counters[2]; 687132718Skan } 688132718Skan else 689132718Skan counters[2] -= counter; 690132718Skan counters[3] += all; 691132718Skan } 692132718Skan} 693132718Skan#endif /* L_gcov_merge_delta */ 694132718Skan 695169689Skan#ifdef L_gcov_interval_profiler 696169689Skan/* If VALUE is in interval <START, START + STEPS - 1>, then increases the 697169689Skan corresponding counter in COUNTERS. If the VALUE is above or below 698169689Skan the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased 699169689Skan instead. */ 700169689Skan 701169689Skanvoid 702169689Skan__gcov_interval_profiler (gcov_type *counters, gcov_type value, 703169689Skan int start, unsigned steps) 704169689Skan{ 705169689Skan gcov_type delta = value - start; 706169689Skan if (delta < 0) 707169689Skan counters[steps + 1]++; 708169689Skan else if (delta >= steps) 709169689Skan counters[steps]++; 710169689Skan else 711169689Skan counters[delta]++; 712169689Skan} 713169689Skan#endif 714169689Skan 715169689Skan#ifdef L_gcov_pow2_profiler 716169689Skan/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise 717169689Skan COUNTERS[0] is incremented. */ 718169689Skan 719169689Skanvoid 720169689Skan__gcov_pow2_profiler (gcov_type *counters, gcov_type value) 721169689Skan{ 722169689Skan if (value & (value - 1)) 723169689Skan counters[0]++; 724169689Skan else 725169689Skan counters[1]++; 726169689Skan} 727169689Skan#endif 728169689Skan 729169689Skan#ifdef L_gcov_one_value_profiler 730169689Skan/* Tries to determine the most common value among its inputs. Checks if the 731169689Skan value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] 732169689Skan is incremented. If this is not the case and COUNTERS[1] is not zero, 733169689Skan COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and 734169689Skan VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this 735169689Skan function is called more than 50% of the time with one value, this value 736169689Skan will be in COUNTERS[0] in the end. 737169689Skan 738169689Skan In any case, COUNTERS[2] is incremented. */ 739169689Skan 740169689Skanvoid 741169689Skan__gcov_one_value_profiler (gcov_type *counters, gcov_type value) 742169689Skan{ 743169689Skan if (value == counters[0]) 744169689Skan counters[1]++; 745169689Skan else if (counters[1] == 0) 746169689Skan { 747169689Skan counters[1] = 1; 748169689Skan counters[0] = value; 749169689Skan } 750169689Skan else 751169689Skan counters[1]--; 752169689Skan counters[2]++; 753169689Skan} 754169689Skan#endif 755169689Skan 756169689Skan#ifdef L_gcov_fork 757169689Skan/* A wrapper for the fork function. Flushes the accumulated profiling data, so 758169689Skan that they are not counted twice. */ 759169689Skan 760169689Skanpid_t 761169689Skan__gcov_fork (void) 762169689Skan{ 763169689Skan __gcov_flush (); 764169689Skan return fork (); 765169689Skan} 766169689Skan#endif 767169689Skan 768169689Skan#ifdef L_gcov_execl 769169689Skan/* A wrapper for the execl function. Flushes the accumulated profiling data, so 770169689Skan that they are not lost. */ 771169689Skan 772169689Skanint 773169689Skan__gcov_execl (const char *path, const char *arg, ...) 774169689Skan{ 775169689Skan va_list ap, aq; 776169689Skan unsigned i, length; 777169689Skan char **args; 778169689Skan 779169689Skan __gcov_flush (); 780169689Skan 781169689Skan va_start (ap, arg); 782169689Skan va_copy (aq, ap); 783169689Skan 784169689Skan length = 2; 785169689Skan while (va_arg (ap, char *)) 786169689Skan length++; 787169689Skan va_end (ap); 788169689Skan 789169689Skan args = (char **) alloca (length * sizeof (void *)); 790169689Skan args[0] = (char *) arg; 791169689Skan for (i = 1; i < length; i++) 792169689Skan args[i] = va_arg (aq, char *); 793169689Skan va_end (aq); 794169689Skan 795169689Skan return execv (path, args); 796169689Skan} 797169689Skan#endif 798169689Skan 799169689Skan#ifdef L_gcov_execlp 800169689Skan/* A wrapper for the execlp function. Flushes the accumulated profiling data, so 801169689Skan that they are not lost. */ 802169689Skan 803169689Skanint 804169689Skan__gcov_execlp (const char *path, const char *arg, ...) 805169689Skan{ 806169689Skan va_list ap, aq; 807169689Skan unsigned i, length; 808169689Skan char **args; 809169689Skan 810169689Skan __gcov_flush (); 811169689Skan 812169689Skan va_start (ap, arg); 813169689Skan va_copy (aq, ap); 814169689Skan 815169689Skan length = 2; 816169689Skan while (va_arg (ap, char *)) 817169689Skan length++; 818169689Skan va_end (ap); 819169689Skan 820169689Skan args = (char **) alloca (length * sizeof (void *)); 821169689Skan args[0] = (char *) arg; 822169689Skan for (i = 1; i < length; i++) 823169689Skan args[i] = va_arg (aq, char *); 824169689Skan va_end (aq); 825169689Skan 826169689Skan return execvp (path, args); 827169689Skan} 828169689Skan#endif 829169689Skan 830169689Skan#ifdef L_gcov_execle 831169689Skan/* A wrapper for the execle function. Flushes the accumulated profiling data, so 832169689Skan that they are not lost. */ 833169689Skan 834169689Skanint 835169689Skan__gcov_execle (const char *path, const char *arg, ...) 836169689Skan{ 837169689Skan va_list ap, aq; 838169689Skan unsigned i, length; 839169689Skan char **args; 840169689Skan char **envp; 841169689Skan 842169689Skan __gcov_flush (); 843169689Skan 844169689Skan va_start (ap, arg); 845169689Skan va_copy (aq, ap); 846169689Skan 847169689Skan length = 2; 848169689Skan while (va_arg (ap, char *)) 849169689Skan length++; 850169689Skan va_end (ap); 851169689Skan 852169689Skan args = (char **) alloca (length * sizeof (void *)); 853169689Skan args[0] = (char *) arg; 854169689Skan for (i = 1; i < length; i++) 855169689Skan args[i] = va_arg (aq, char *); 856169689Skan envp = va_arg (aq, char **); 857169689Skan va_end (aq); 858169689Skan 859169689Skan return execve (path, args, envp); 860169689Skan} 861169689Skan#endif 862169689Skan 863169689Skan#ifdef L_gcov_execv 864169689Skan/* A wrapper for the execv function. Flushes the accumulated profiling data, so 865169689Skan that they are not lost. */ 866169689Skan 867169689Skanint 868169689Skan__gcov_execv (const char *path, char *const argv[]) 869169689Skan{ 870169689Skan __gcov_flush (); 871169689Skan return execv (path, argv); 872169689Skan} 873169689Skan#endif 874169689Skan 875169689Skan#ifdef L_gcov_execvp 876169689Skan/* A wrapper for the execvp function. Flushes the accumulated profiling data, so 877169689Skan that they are not lost. */ 878169689Skan 879169689Skanint 880169689Skan__gcov_execvp (const char *path, char *const argv[]) 881169689Skan{ 882169689Skan __gcov_flush (); 883169689Skan return execvp (path, argv); 884169689Skan} 885169689Skan#endif 886169689Skan 887169689Skan#ifdef L_gcov_execve 888169689Skan/* A wrapper for the execve function. Flushes the accumulated profiling data, so 889169689Skan that they are not lost. */ 890169689Skan 891169689Skanint 892169689Skan__gcov_execve (const char *path, char *const argv[], char *const envp[]) 893169689Skan{ 894169689Skan __gcov_flush (); 895169689Skan return execve (path, argv, envp); 896169689Skan} 897169689Skan#endif 898132718Skan#endif /* inhibit_libc */ 899