1  /* Header file for libgcov-*.c.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of GCC.
       5  
       6     GCC is free software; you can redistribute it and/or modify it under
       7     the terms of the GNU General Public License as published by the Free
       8     Software Foundation; either version 3, or (at your option) any later
       9     version.
      10  
      11     GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12     WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14     for more details.
      15  
      16     Under Section 7 of GPL version 3, you are granted additional
      17     permissions described in the GCC Runtime Library Exception, version
      18     3.1, as published by the Free Software Foundation.
      19  
      20     You should have received a copy of the GNU General Public License and
      21     a copy of the GCC Runtime Library Exception along with this program;
      22     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23     <http://www.gnu.org/licenses/>.  */
      24  
      25  #ifndef GCC_LIBGCOV_H
      26  #define GCC_LIBGCOV_H
      27  
      28  /* work around the poisoned malloc/calloc in system.h.  */
      29  #ifndef xmalloc
      30  #define xmalloc malloc
      31  #endif
      32  #ifndef xcalloc
      33  #define xcalloc calloc
      34  #endif
      35  
      36  #ifndef IN_GCOV_TOOL
      37  /* About the target.  */
      38  /* This path will be used by libgcov runtime.  */
      39  
      40  #include "tconfig.h"
      41  #include "auto-target.h"
      42  #include "tsystem.h"
      43  #include "coretypes.h"
      44  #include "tm.h"
      45  #include "libgcc_tm.h"
      46  #include "gcov.h"
      47  
      48  #if HAVE_SYS_MMAN_H
      49  #include <sys/mman.h>
      50  #endif
      51  
      52  #if __CHAR_BIT__ == 8
      53  typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
      54  typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
      55  #if __LIBGCC_GCOV_TYPE_SIZE > 32
      56  typedef signed gcov_type __attribute__ ((mode (DI)));
      57  typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
      58  #else
      59  typedef signed gcov_type __attribute__ ((mode (SI)));
      60  typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
      61  #endif
      62  #else
      63  #if __CHAR_BIT__ == 16
      64  typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
      65  typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
      66  #if __LIBGCC_GCOV_TYPE_SIZE > 32
      67  typedef signed gcov_type __attribute__ ((mode (SI)));
      68  typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
      69  #else
      70  typedef signed gcov_type __attribute__ ((mode (HI)));
      71  typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
      72  #endif
      73  #else
      74  typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
      75  typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
      76  #if __LIBGCC_GCOV_TYPE_SIZE > 32
      77  typedef signed gcov_type __attribute__ ((mode (HI)));
      78  typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
      79  #else
      80  typedef signed gcov_type __attribute__ ((mode (QI)));
      81  typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
      82  #endif
      83  #endif
      84  #endif
      85  
      86  #if defined (TARGET_POSIX_IO)
      87  #define GCOV_LOCKED 1
      88  #else
      89  #define GCOV_LOCKED 0
      90  #endif
      91  
      92  #if defined (__MSVCRT__)
      93  #define GCOV_LOCKED_WITH_LOCKING 1
      94  #else
      95  #define GCOV_LOCKED_WITH_LOCKING 0
      96  #endif
      97  
      98  #ifndef GCOV_SUPPORTS_ATOMIC
      99  /* Detect whether target can support atomic update of profilers.  */
     100  #if __SIZEOF_LONG_LONG__ == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
     101  #define GCOV_SUPPORTS_ATOMIC 1
     102  #else
     103  #if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
     104  #define GCOV_SUPPORTS_ATOMIC 1
     105  #else
     106  #define GCOV_SUPPORTS_ATOMIC 0
     107  #endif
     108  #endif
     109  #endif
     110  
     111  /* In libgcov we need these functions to be extern, so prefix them with
     112     __gcov.  In libgcov they must also be hidden so that the instance in
     113     the executable is not also used in a DSO.  */
     114  #define gcov_var __gcov_var
     115  #define gcov_open __gcov_open
     116  #define gcov_close __gcov_close
     117  #define gcov_position __gcov_position
     118  #define gcov_rewrite __gcov_rewrite
     119  #define gcov_is_error __gcov_is_error
     120  #define gcov_write_unsigned __gcov_write_unsigned
     121  #define gcov_write_object_summary __gcov_write_object_summary
     122  #define gcov_read_unsigned __gcov_read_unsigned
     123  #define gcov_read_counter __gcov_read_counter
     124  #define gcov_read_summary __gcov_read_summary
     125  
     126  #else /* IN_GCOV_TOOL */
     127  /* About the host.  */
     128  /* This path will be compiled for the host and linked into
     129     gcov-tool binary.  */
     130  
     131  #include "config.h"
     132  #include "system.h"
     133  #include "coretypes.h"
     134  #include "tm.h"
     135  
     136  typedef unsigned gcov_unsigned_t;
     137  typedef unsigned gcov_position_t;
     138  /* gcov_type is typedef'd elsewhere for the compiler */
     139  
     140  #if defined (HOST_HAS_F_SETLKW)
     141  #define GCOV_LOCKED 1
     142  #else
     143  #define GCOV_LOCKED 0
     144  #endif
     145  
     146  #if defined (HOST_HAS_LK_LOCK)
     147  #define GCOV_LOCKED_WITH_LOCKING 1
     148  #else
     149  #define GCOV_LOCKED_WITH_LOCKING 0
     150  #endif
     151  
     152  /* Some Macros specific to gcov-tool.  */
     153  
     154  #define L_gcov 1
     155  #define L_gcov_merge_add 1
     156  #define L_gcov_merge_topn 1
     157  #define L_gcov_merge_ior 1
     158  #define L_gcov_merge_time_profile 1
     159  
     160  extern gcov_type gcov_read_counter_mem ();
     161  extern unsigned gcov_get_merge_weight ();
     162  extern struct gcov_info *gcov_list;
     163  
     164  #endif /* !IN_GCOV_TOOL */
     165  
     166  #if defined(inhibit_libc)
     167  #define IN_LIBGCOV (-1)
     168  #else
     169  #define IN_LIBGCOV 1
     170  #if defined(L_gcov)
     171  #define GCOV_LINKAGE /* nothing */
     172  #endif
     173  #endif
     174  
     175  /* Poison these, so they don't accidentally slip in.  */
     176  #pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
     177  #pragma GCC poison gcov_time
     178  
     179  #ifdef HAVE_GAS_HIDDEN
     180  #define ATTRIBUTE_HIDDEN  __attribute__ ((__visibility__ ("hidden")))
     181  #else
     182  #define ATTRIBUTE_HIDDEN
     183  #endif
     184  
     185  #if HAVE_SYS_MMAN_H
     186  #ifndef MAP_FAILED
     187  #define MAP_FAILED ((void *)-1)
     188  #endif
     189  
     190  #if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
     191  #define MAP_ANONYMOUS MAP_ANON
     192  #endif
     193  #endif
     194  
     195  #include "gcov-io.h"
     196  
     197  /* Structures embedded in coveraged program.  The structures generated
     198     by write_profile must match these.  */
     199  
     200  /* Information about counters for a single function.  */
     201  struct gcov_ctr_info
     202  {
     203    gcov_unsigned_t num;		/* number of counters.  */
     204    gcov_type *values;		/* their values.  */
     205  };
     206  
     207  /* Information about a single function.  This uses the trailing array
     208     idiom. The number of counters is determined from the merge pointer
     209     array in gcov_info.  The key is used to detect which of a set of
     210     comdat functions was selected -- it points to the gcov_info object
     211     of the object file containing the selected comdat function.  */
     212  
     213  struct gcov_fn_info
     214  {
     215    const struct gcov_info *key;		/* comdat key */
     216    gcov_unsigned_t ident;		/* unique ident of function */
     217    gcov_unsigned_t lineno_checksum;	/* function lineo_checksum */
     218    gcov_unsigned_t cfg_checksum;		/* function cfg checksum */
     219    struct gcov_ctr_info ctrs[1];		/* instrumented counters */
     220  };
     221  
     222  /* Type of function used to merge counters.  */
     223  typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
     224  
     225  /* Information about a single object file.  */
     226  struct gcov_info
     227  {
     228    gcov_unsigned_t version;	/* expected version number */
     229    struct gcov_info *next;	/* link to next, used by libgcov */
     230  
     231    gcov_unsigned_t stamp;	/* uniquifying time stamp */
     232    gcov_unsigned_t checksum;	/* unique object checksum */
     233    const char *filename;		/* output file name */
     234  
     235    gcov_merge_fn merge[GCOV_COUNTERS];  /* merge functions (null for
     236  					  unused) */
     237    
     238    gcov_unsigned_t n_functions;		/* number of functions */
     239  
     240  #ifndef IN_GCOV_TOOL
     241    const struct gcov_fn_info *const *functions; /* pointer to pointers
     242                                                    to function information  */
     243  #else
     244    struct gcov_fn_info **functions;
     245    struct gcov_summary summary;
     246  #endif /* !IN_GCOV_TOOL */
     247  };
     248  
     249  /* Root of a program/shared-object state */
     250  struct gcov_root
     251  {
     252    struct gcov_info *list;
     253    unsigned dumped : 1;	/* counts have been dumped.  */
     254    unsigned run_counted : 1;  /* run has been accounted for.  */
     255    struct gcov_root *next;
     256    struct gcov_root *prev;
     257  };
     258  
     259  extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN;
     260  
     261  struct gcov_master
     262  {
     263    gcov_unsigned_t version;
     264    struct gcov_root *root;
     265  };
     266  
     267  struct indirect_call_tuple
     268  {
     269    /* Callee function.  */
     270    void *callee;
     271  
     272    /* Pointer to counters.  */
     273    gcov_type *counters;
     274  };
     275    
     276  /* Exactly one of these will be active in the process.  */
     277  extern struct gcov_master __gcov_master;
     278  extern struct gcov_kvp *__gcov_kvp_dynamic_pool;
     279  extern unsigned __gcov_kvp_dynamic_pool_index;
     280  extern unsigned __gcov_kvp_dynamic_pool_size;
     281  
     282  /* Dump a set of gcov objects.  */
     283  extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN;
     284  
     285  /* Register a new object file module.  */
     286  extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
     287  
     288  /* GCOV exit function registered via a static destructor.  */
     289  extern void __gcov_exit (void) ATTRIBUTE_HIDDEN;
     290  
     291  /* Function to reset all counters to 0.  Both externally visible (and
     292     overridable) and internal version.  */
     293  extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN;
     294  
     295  /* User function to enable early write of profile information so far.  */
     296  extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN;
     297  
     298  /* Lock critical section for __gcov_dump and __gcov_reset functions.  */
     299  extern void __gcov_lock (void) ATTRIBUTE_HIDDEN;
     300  
     301  /* Unlock critical section for __gcov_dump and __gcov_reset functions.  */
     302  extern void __gcov_unlock (void) ATTRIBUTE_HIDDEN;
     303  
     304  /* The merge function that just sums the counters.  */
     305  extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
     306  
     307  /* The merge function to select the minimum valid counter value.  */
     308  extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
     309  
     310  /* The merge function to choose the most common N values.  */
     311  extern void __gcov_merge_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
     312  
     313  /* The merge function that just ors the counters together.  */
     314  extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
     315  
     316  /* The profiler functions.  */
     317  extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
     318  extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int,
     319  					     unsigned);
     320  extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
     321  extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type);
     322  extern void __gcov_topn_values_profiler (gcov_type *, gcov_type);
     323  extern void __gcov_topn_values_profiler_atomic (gcov_type *, gcov_type);
     324  extern void __gcov_indirect_call_profiler_v4 (gcov_type, void *);
     325  extern void __gcov_indirect_call_profiler_v4_atomic (gcov_type, void *);
     326  extern void __gcov_time_profiler (gcov_type *);
     327  extern void __gcov_time_profiler_atomic (gcov_type *);
     328  extern void __gcov_average_profiler (gcov_type *, gcov_type);
     329  extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
     330  extern void __gcov_ior_profiler (gcov_type *, gcov_type);
     331  extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
     332  
     333  #ifndef inhibit_libc
     334  /* The wrappers around some library functions..  */
     335  extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
     336  extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN;
     337  extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN;
     338  extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN;
     339  extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN;
     340  extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
     341  extern int __gcov_execve (const char *, char  *const [], char *const [])
     342    ATTRIBUTE_HIDDEN;
     343  
     344  /* Functions that only available in libgcov.  */
     345  GCOV_LINKAGE void gcov_write_object_summary (const struct gcov_summary *)
     346      ATTRIBUTE_HIDDEN;
     347  GCOV_LINKAGE void gcov_rewrite (void) ATTRIBUTE_HIDDEN;
     348  
     349  /* "Counts" stored in gcda files can be a real counter value, or
     350     an target address. When differentiate these two types because
     351     when manipulating counts, we should only change real counter values,
     352     rather target addresses.  */
     353  
     354  static inline gcov_type
     355  gcov_get_counter (void)
     356  {
     357  #ifndef IN_GCOV_TOOL
     358    /* This version is for reading count values in libgcov runtime:
     359       we read from gcda files.  */
     360  
     361    return gcov_read_counter ();
     362  #else
     363    /* This version is for gcov-tool. We read the value from memory and
     364       multiply it by the merge weight.  */
     365  
     366    return gcov_read_counter_mem () * gcov_get_merge_weight ();
     367  #endif
     368  }
     369  
     370  /* Similar function as gcov_get_counter(), but do not scale
     371     when read value is equal to IGNORE_SCALING.  */
     372  
     373  static inline gcov_type
     374  gcov_get_counter_ignore_scaling (gcov_type ignore_scaling ATTRIBUTE_UNUSED)
     375  {
     376  #ifndef IN_GCOV_TOOL
     377    /* This version is for reading count values in libgcov runtime:
     378       we read from gcda files.  */
     379  
     380    return gcov_read_counter ();
     381  #else
     382    /* This version is for gcov-tool. We read the value from memory and
     383       multiply it by the merge weight.  */
     384  
     385    gcov_type v = gcov_read_counter_mem ();
     386    if (v != ignore_scaling)
     387      v *= gcov_get_merge_weight ();
     388  
     389    return v;
     390  #endif
     391  }
     392  
     393  /* Similar function as gcov_get_counter(), but handles target address
     394     counters.  */
     395  
     396  static inline gcov_type
     397  gcov_get_counter_target (void)
     398  {
     399  #ifndef IN_GCOV_TOOL
     400    /* This version is for reading count target values in libgcov runtime:
     401       we read from gcda files.  */
     402  
     403    return gcov_read_counter ();
     404  #else
     405    /* This version is for gcov-tool.  We read the value from memory and we do NOT
     406       multiply it by the merge weight.  */
     407  
     408    return gcov_read_counter_mem ();
     409  #endif
     410  }
     411  
     412  /* Add VALUE to *COUNTER and make it with atomic operation
     413     if USE_ATOMIC is true.  */
     414  
     415  static inline void
     416  gcov_counter_add (gcov_type *counter, gcov_type value,
     417  		  int use_atomic ATTRIBUTE_UNUSED)
     418  {
     419  #if GCOV_SUPPORTS_ATOMIC
     420    if (use_atomic)
     421      __atomic_fetch_add (counter, value, __ATOMIC_RELAXED);
     422    else
     423  #endif
     424      *counter += value;
     425  }
     426  
     427  #if HAVE_SYS_MMAN_H
     428  
     429  /* Allocate LENGTH with mmap function.  */
     430  
     431  static inline void *
     432  malloc_mmap (size_t length)
     433  {
     434    return mmap (NULL, length, PROT_READ | PROT_WRITE,
     435  	       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     436  }
     437  
     438  #endif
     439  
     440  /* Allocate gcov_kvp from statically pre-allocated pool,
     441     or use heap otherwise.  */
     442  
     443  static inline struct gcov_kvp *
     444  allocate_gcov_kvp (void)
     445  {
     446  #define MMAP_CHUNK_SIZE	(128 * 1024)
     447    struct gcov_kvp *new_node = NULL;
     448    unsigned kvp_sizeof = sizeof(struct gcov_kvp);
     449  
     450    /* Try mmaped pool if available.  */
     451  #if !defined(IN_GCOV_TOOL) && !defined(L_gcov_merge_topn) && HAVE_SYS_MMAN_H
     452    if (__gcov_kvp_dynamic_pool == NULL
     453        || __gcov_kvp_dynamic_pool_index >= __gcov_kvp_dynamic_pool_size)
     454      {
     455        void *ptr = malloc_mmap (MMAP_CHUNK_SIZE);
     456        if (ptr != MAP_FAILED)
     457  	{
     458  	  __gcov_kvp_dynamic_pool = ptr;
     459  	  __gcov_kvp_dynamic_pool_size = MMAP_CHUNK_SIZE / kvp_sizeof;
     460  	  __gcov_kvp_dynamic_pool_index = 0;
     461  	}
     462      }
     463  
     464    if (__gcov_kvp_dynamic_pool != NULL)
     465      {
     466        unsigned index;
     467  #if GCOV_SUPPORTS_ATOMIC
     468        index
     469  	= __atomic_fetch_add (&__gcov_kvp_dynamic_pool_index, 1,
     470  			      __ATOMIC_RELAXED);
     471  #else
     472        index = __gcov_kvp_dynamic_pool_index++;
     473  #endif
     474        if (index < __gcov_kvp_dynamic_pool_size)
     475  	new_node = __gcov_kvp_dynamic_pool + index;
     476      }
     477  #endif
     478  
     479    /* Fallback to malloc.  */
     480    if (new_node == NULL)
     481      new_node = (struct gcov_kvp *)xcalloc (1, kvp_sizeof);
     482  
     483    return new_node;
     484  }
     485  
     486  /* Add key value pair VALUE:COUNT to a top N COUNTERS.  When INCREMENT_TOTAL
     487     is true, add COUNT to total of the TOP counter.  If USE_ATOMIC is true,
     488     do it in atomic way.  Return true when the counter is full, otherwise
     489     return false.  */
     490  
     491  static inline unsigned
     492  gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count,
     493  		     int use_atomic, int increment_total)
     494  {
     495    if (increment_total)
     496      {
     497        /* In the multi-threaded mode, we can have an already merged profile
     498  	 with a negative total value.  In that case, we should bail out.  */
     499        if (counters[0] < 0)
     500  	return 0;
     501        gcov_counter_add (&counters[0], 1, use_atomic);
     502      }
     503  
     504    struct gcov_kvp *prev_node = NULL;
     505    struct gcov_kvp *minimal_node = NULL;
     506    struct gcov_kvp *current_node  = (struct gcov_kvp *)(intptr_t)counters[2];
     507  
     508    while (current_node)
     509      {
     510        if (current_node->value == value)
     511  	{
     512  	  gcov_counter_add (¤t_node->count, count, use_atomic);
     513  	  return 0;
     514  	}
     515  
     516        if (minimal_node == NULL
     517  	  || current_node->count < minimal_node->count)
     518  	minimal_node = current_node;
     519  
     520        prev_node = current_node;
     521        current_node = current_node->next;
     522      }
     523  
     524    if (counters[1] == GCOV_TOPN_MAXIMUM_TRACKED_VALUES)
     525      {
     526        if (--minimal_node->count < count)
     527  	{
     528  	  minimal_node->value = value;
     529  	  minimal_node->count = count;
     530  	}
     531  
     532        return 1;
     533      }
     534    else
     535      {
     536        struct gcov_kvp *new_node = allocate_gcov_kvp ();
     537        if (new_node == NULL)
     538  	return 0;
     539  
     540        new_node->value = value;
     541        new_node->count = count;
     542  
     543        int success = 0;
     544        if (!counters[2])
     545  	{
     546  #if GCOV_SUPPORTS_ATOMIC
     547  	  if (use_atomic)
     548  	    {
     549  	      struct gcov_kvp **ptr = (struct gcov_kvp **)(intptr_t)&counters[2];
     550  	      success = !__sync_val_compare_and_swap (ptr, 0, new_node);
     551  	    }
     552  	  else
     553  #endif
     554  	    {
     555  	      counters[2] = (intptr_t)new_node;
     556  	      success = 1;
     557  	    }
     558  	}
     559        else if (prev_node && !prev_node->next)
     560  	{
     561  #if GCOV_SUPPORTS_ATOMIC
     562  	  if (use_atomic)
     563  	    success = !__sync_val_compare_and_swap (&prev_node->next, 0,
     564  						    new_node);
     565  	  else
     566  #endif
     567  	    {
     568  	      prev_node->next = new_node;
     569  	      success = 1;
     570  	    }
     571  	}
     572  
     573        /* Increment number of nodes.  */
     574        if (success)
     575  	gcov_counter_add (&counters[1], 1, use_atomic);
     576      }
     577  
     578    return 0;
     579  }
     580  
     581  #endif /* !inhibit_libc */
     582  
     583  #endif /* GCC_LIBGCOV_H */