/* Routines required for instrumenting a program. */ /* Compile this one with gcc. */ /* Copyright (C) 1989-2014 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "libgcov.h" #include "gthr.h" #if defined(inhibit_libc) #ifdef L_gcov_flush void __gcov_flush (void) {} #endif #ifdef L_gcov_reset void __gcov_reset (void) {} #endif #ifdef L_gcov_dump void __gcov_dump (void) {} #endif #else extern void gcov_clear (void) ATTRIBUTE_HIDDEN; extern void gcov_exit (void) ATTRIBUTE_HIDDEN; extern void set_gcov_dump_complete (void) ATTRIBUTE_HIDDEN; extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN; #ifdef L_gcov_flush #ifdef __GTHREAD_MUTEX_INIT ATTRIBUTE_HIDDEN __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; #define init_mx_once() #else __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; static void init_mx (void) { __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); } static void init_mx_once (void) { static __gthread_once_t once = __GTHREAD_ONCE_INIT; __gthread_once (&once, init_mx); } #endif /* Called before fork or exec - write out profile information gathered so far and reset it to zero. This avoids duplication or loss of the profile information gathered so far. */ void __gcov_flush (void) { init_mx_once (); __gthread_mutex_lock (&__gcov_flush_mx); gcov_exit (); gcov_clear (); __gthread_mutex_unlock (&__gcov_flush_mx); } #endif /* L_gcov_flush */ #ifdef L_gcov_reset /* Function that can be called from application to reset counters to zero, in order to collect profile in region of interest. */ void __gcov_reset (void) { gcov_clear (); /* Re-enable dumping to support collecting profile in multiple regions of interest. */ reset_gcov_dump_complete (); } #endif /* L_gcov_reset */ #ifdef L_gcov_dump /* Function that can be called from application to write profile collected so far, in order to collect profile in region of interest. */ void __gcov_dump (void) { gcov_exit (); /* Prevent profile from being dumped a second time on application exit. */ set_gcov_dump_complete (); } /* Emitted in coverage.c. */ extern gcov_unsigned_t __gcov_test_coverage; unsigned int __gcov_profiling_for_test_coverage (void); /* Function that can be called from application to distinguish binaries instrumented for coverage from those instrumented for profile optimization (e.g. -fprofile-generate). */ unsigned int __gcov_profiling_for_test_coverage (void) { return __gcov_test_coverage; } typedef void (*gcov_dumper_type) (void); struct dumper_entry { gcov_dumper_type dumper; struct dumper_entry *next_dumper; }; static struct dumper_entry this_dumper = {&__gcov_dump, 0}; /* global dumper list with default visibilty. */ struct dumper_entry *__gcov_dumper_list; #ifdef __GTHREAD_MUTEX_INIT __gthread_mutex_t __gcov_dump_mx = __GTHREAD_MUTEX_INIT; #define init_mx_once() #else __gthread_mutex_t __gcov_dump_mx; static void init_mx (void) { __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_dump_mx); } static void init_mx_once (void) { static __gthread_once_t once = __GTHREAD_ONCE_INIT; __gthread_once (&once, init_mx); } #endif /* Register the library private __gcov_dump method to the global list. */ __attribute__((constructor)) static void register_dumper (void) { init_mx_once (); __gthread_mutex_lock (&__gcov_dump_mx); this_dumper.next_dumper = __gcov_dumper_list; __gcov_dumper_list = &this_dumper; __gthread_mutex_unlock (&__gcov_dump_mx); } __attribute__((destructor)) static void unregister_dumper (void) { struct dumper_entry *dumper; struct dumper_entry *prev_dumper = 0; init_mx_once (); __gthread_mutex_lock (&__gcov_dump_mx); dumper = __gcov_dumper_list; while (dumper) { if (dumper->dumper == &__gcov_dump) { if (prev_dumper) prev_dumper->next_dumper = dumper->next_dumper; else __gcov_dumper_list = dumper->next_dumper; break; } prev_dumper = dumper; dumper = dumper->next_dumper; } __gthread_mutex_unlock (&__gcov_dump_mx); } /* Public interface to dump profile data for all shared libraries via registered dumpers from the libraries. This interface has default visibility (unlike gcov_dump which has hidden visbility. */ void __gcov_dump_all (void) { struct dumper_entry *dumper; init_mx_once (); __gthread_mutex_lock (&__gcov_dump_mx); dumper = __gcov_dumper_list; while (dumper) { dumper->dumper (); dumper = dumper->next_dumper; } __gthread_mutex_unlock (&__gcov_dump_mx); } #endif /* L_gcov_dump */ #ifdef L_gcov_sampling /* Emitted in coverage.c. */ /* Sampling period. */ extern gcov_unsigned_t __gcov_sampling_period; extern gcov_unsigned_t __gcov_has_sampling; void __gcov_set_sampling_period (unsigned int period); unsigned int __gcov_sampling_enabled (); /* Per thread sample counter. */ __thread gcov_unsigned_t __gcov_sample_counter = 0; /* Set sampling period to PERIOD. */ void __gcov_set_sampling_period (unsigned int period) { gcc_assert (__gcov_has_sampling); __gcov_sampling_period = period; } unsigned int __gcov_sampling_enabled () { return __gcov_has_sampling; } #endif #ifdef L_gcov_prefix /* Profile directory prefix specified to -fprofile-generate=. */ extern char * __gcov_profile_prefix; char *__gcov_get_profile_prefix () { return __gcov_profile_prefix; } #endif #ifdef L_gcov_fork /* A wrapper for the fork function. Flushes the accumulated profiling data, so that they are not counted twice. */ pid_t __gcov_fork (void) { pid_t pid; extern __gthread_mutex_t __gcov_flush_mx; __gcov_flush (); pid = fork (); if (pid == 0) __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); return pid; } #endif #ifdef L_gcov_execl /* A wrapper for the execl function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execl (const char *path, char *arg, ...) { va_list ap, aq; unsigned i, length; char **args; __gcov_flush (); va_start (ap, arg); va_copy (aq, ap); length = 2; while (va_arg (ap, char *)) length++; va_end (ap); args = (char **) alloca (length * sizeof (void *)); args[0] = arg; for (i = 1; i < length; i++) args[i] = va_arg (aq, char *); va_end (aq); return execv (path, args); } #endif #ifdef L_gcov_execlp /* A wrapper for the execlp function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execlp (const char *path, char *arg, ...) { va_list ap, aq; unsigned i, length; char **args; __gcov_flush (); va_start (ap, arg); va_copy (aq, ap); length = 2; while (va_arg (ap, char *)) length++; va_end (ap); args = (char **) alloca (length * sizeof (void *)); args[0] = arg; for (i = 1; i < length; i++) args[i] = va_arg (aq, char *); va_end (aq); return execvp (path, args); } #endif #ifdef L_gcov_execle /* A wrapper for the execle function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execle (const char *path, char *arg, ...) { va_list ap, aq; unsigned i, length; char **args; char **envp; __gcov_flush (); va_start (ap, arg); va_copy (aq, ap); length = 2; while (va_arg (ap, char *)) length++; va_end (ap); args = (char **) alloca (length * sizeof (void *)); args[0] = arg; for (i = 1; i < length; i++) args[i] = va_arg (aq, char *); envp = va_arg (aq, char **); va_end (aq); return execve (path, args, envp); } #endif #ifdef L_gcov_execv /* A wrapper for the execv function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execv (const char *path, char *const argv[]) { __gcov_flush (); return execv (path, argv); } #endif #ifdef L_gcov_execvp /* A wrapper for the execvp function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execvp (const char *path, char *const argv[]) { __gcov_flush (); return execvp (path, argv); } #endif #ifdef L_gcov_execve /* A wrapper for the execve function. Flushes the accumulated profiling data, so that they are not lost. */ int __gcov_execve (const char *path, char *const argv[], char *const envp[]) { __gcov_flush (); return execve (path, argv, envp); } #endif #endif /* inhibit_libc */