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