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