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 (¤t_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