1 /* Routines required for instrumenting a program. */ 2 /* Compile this one with gcc. */ 3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see 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 32 void __gcov_flush (void) {} 33 #endif 34 35 #ifdef L_gcov_reset 36 void __gcov_reset (void) {} 37 #endif 38 39 #ifdef L_gcov_dump 40 void __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 54 extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN; 55 extern __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 64 static void 65 init_mx (void) 66 { 67 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); 68 } 69 70 static void 71 init_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 82 void 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 100 static void 101 gcov_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 132 void 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 147 ALIAS_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 155 void 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 167 ALIAS_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 175 pid_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 191 int 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 222 int 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 253 int 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 286 int 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 298 int 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 310 int 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