1/* Routines required for instrumenting a program. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1989-2015 Free Software Foundation, Inc. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 3, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24<http://www.gnu.org/licenses/>. */ 25 26#include "libgcov.h" 27#include "gthr.h" 28 29#if defined(inhibit_libc) 30 31#ifdef L_gcov_flush 32void __gcov_flush (void) {} 33#endif 34 35#ifdef L_gcov_reset 36void __gcov_reset (void) {} 37#endif 38 39#ifdef L_gcov_dump 40void __gcov_dump (void) {} 41#endif 42 43#else 44 45/* Some functions we want to bind in this dynamic object, but have an 46 overridable global alias. Unfortunately not all targets support 47 aliases, so we just have a forwarding function. That'll be tail 48 called, so the cost is a single jump instruction.*/ 49 50#define ALIAS_void_fn(src,dst) \ 51 void dst (void) \ 52 { src (); } 53 54extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; 55extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; 56 57#ifdef L_gcov_flush 58#ifdef __GTHREAD_MUTEX_INIT 59__gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; 60#define init_mx_once() 61#else 62__gthread_mutex_t __gcov_flush_mx; 63 64static void 65init_mx (void) 66{ 67 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); 68} 69 70static void 71init_mx_once (void) 72{ 73 static __gthread_once_t once = __GTHREAD_ONCE_INIT; 74 __gthread_once (&once, init_mx); 75} 76#endif 77 78/* Called before fork or exec - write out profile information gathered so 79 far and reset it to zero. This avoids duplication or loss of the 80 profile information gathered so far. */ 81 82void 83__gcov_flush (void) 84{ 85 init_mx_once (); 86 __gthread_mutex_lock (&__gcov_flush_mx); 87 88 __gcov_dump_int (); 89 __gcov_reset_int (); 90 91 __gthread_mutex_unlock (&__gcov_flush_mx); 92} 93 94#endif /* L_gcov_flush */ 95 96#ifdef L_gcov_reset 97 98/* Reset all counters to zero. */ 99 100static void 101gcov_clear (const struct gcov_info *list) 102{ 103 const struct gcov_info *gi_ptr; 104 105 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 106 { 107 unsigned f_ix; 108 109 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 110 { 111 unsigned t_ix; 112 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; 113 114 if (!gfi_ptr || gfi_ptr->key != gi_ptr) 115 continue; 116 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; 117 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) 118 { 119 if (!gi_ptr->merge[t_ix]) 120 continue; 121 122 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); 123 ci_ptr++; 124 } 125 } 126 } 127} 128 129/* Function that can be called from application to reset counters to zero, 130 in order to collect profile in region of interest. */ 131 132void 133__gcov_reset_int (void) 134{ 135 struct gcov_root *root; 136 137 /* If we're compatible with the master, iterate over everything, 138 otherise just do us. */ 139 for (root = __gcov_master.version == GCOV_VERSION 140 ? __gcov_master.root : &__gcov_root; root; root = root->next) 141 { 142 gcov_clear (root->list); 143 root->dumped = 0; 144 } 145} 146 147ALIAS_void_fn (__gcov_reset_int, __gcov_reset); 148 149#endif /* L_gcov_reset */ 150 151#ifdef L_gcov_dump 152/* Function that can be called from application to write profile collected 153 so far, in order to collect profile in region of interest. */ 154 155void 156__gcov_dump_int (void) 157{ 158 struct gcov_root *root; 159 160 /* If we're compatible with the master, iterate over everything, 161 otherise just do us. */ 162 for (root = __gcov_master.version == GCOV_VERSION 163 ? __gcov_master.root : &__gcov_root; root; root = root->next) 164 __gcov_dump_one (root); 165} 166 167ALIAS_void_fn (__gcov_dump_int, __gcov_dump); 168 169#endif /* L_gcov_dump */ 170 171#ifdef L_gcov_fork 172/* A wrapper for the fork function. Flushes the accumulated profiling data, so 173 that they are not counted twice. */ 174 175pid_t 176__gcov_fork (void) 177{ 178 pid_t pid; 179 __gcov_flush (); 180 pid = fork (); 181 if (pid == 0) 182 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); 183 return pid; 184} 185#endif 186 187#ifdef L_gcov_execl 188/* A wrapper for the execl function. Flushes the accumulated 189 profiling data, so that they are not lost. */ 190 191int 192__gcov_execl (const char *path, char *arg, ...) 193{ 194 va_list ap, aq; 195 unsigned i, length; 196 char **args; 197 198 __gcov_flush (); 199 200 va_start (ap, arg); 201 va_copy (aq, ap); 202 203 length = 2; 204 while (va_arg (ap, char *)) 205 length++; 206 va_end (ap); 207 208 args = (char **) alloca (length * sizeof (void *)); 209 args[0] = arg; 210 for (i = 1; i < length; i++) 211 args[i] = va_arg (aq, char *); 212 va_end (aq); 213 214 return execv (path, args); 215} 216#endif 217 218#ifdef L_gcov_execlp 219/* A wrapper for the execlp function. Flushes the accumulated 220 profiling data, so that they are not lost. */ 221 222int 223__gcov_execlp (const char *path, char *arg, ...) 224{ 225 va_list ap, aq; 226 unsigned i, length; 227 char **args; 228 229 __gcov_flush (); 230 231 va_start (ap, arg); 232 va_copy (aq, ap); 233 234 length = 2; 235 while (va_arg (ap, char *)) 236 length++; 237 va_end (ap); 238 239 args = (char **) alloca (length * sizeof (void *)); 240 args[0] = arg; 241 for (i = 1; i < length; i++) 242 args[i] = va_arg (aq, char *); 243 va_end (aq); 244 245 return execvp (path, args); 246} 247#endif 248 249#ifdef L_gcov_execle 250/* A wrapper for the execle function. Flushes the accumulated 251 profiling data, so that they are not lost. */ 252 253int 254__gcov_execle (const char *path, char *arg, ...) 255{ 256 va_list ap, aq; 257 unsigned i, length; 258 char **args; 259 char **envp; 260 261 __gcov_flush (); 262 263 va_start (ap, arg); 264 va_copy (aq, ap); 265 266 length = 2; 267 while (va_arg (ap, char *)) 268 length++; 269 va_end (ap); 270 271 args = (char **) alloca (length * sizeof (void *)); 272 args[0] = arg; 273 for (i = 1; i < length; i++) 274 args[i] = va_arg (aq, char *); 275 envp = va_arg (aq, char **); 276 va_end (aq); 277 278 return execve (path, args, envp); 279} 280#endif 281 282#ifdef L_gcov_execv 283/* A wrapper for the execv function. Flushes the accumulated 284 profiling data, so that they are not lost. */ 285 286int 287__gcov_execv (const char *path, char *const argv[]) 288{ 289 __gcov_flush (); 290 return execv (path, argv); 291} 292#endif 293 294#ifdef L_gcov_execvp 295/* A wrapper for the execvp function. Flushes the accumulated 296 profiling data, so that they are not lost. */ 297 298int 299__gcov_execvp (const char *path, char *const argv[]) 300{ 301 __gcov_flush (); 302 return execvp (path, argv); 303} 304#endif 305 306#ifdef L_gcov_execve 307/* A wrapper for the execve function. Flushes the accumulated 308 profiling data, so that they are not lost. */ 309 310int 311__gcov_execve (const char *path, char *const argv[], char *const envp[]) 312{ 313 __gcov_flush (); 314 return execve (path, argv, envp); 315} 316#endif 317#endif /* inhibit_libc */ 318