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