1 /* Routines required for instrumenting a program. */ 2 /* Compile this one with gcc. */ 3 /* Copyright (C) 1989-2020 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 56 #ifdef L_gcov_flush 57 #ifdef __GTHREAD_MUTEX_INIT 58 __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT; 59 #define init_mx_once() 60 #else 61 __gthread_mutex_t __gcov_flush_mx; 62 63 static void 64 init_mx (void) 65 { 66 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); 67 } 68 69 static void 70 init_mx_once (void) 71 { 72 static __gthread_once_t once = __GTHREAD_ONCE_INIT; 73 __gthread_once (&once, init_mx); 74 } 75 #endif 76 77 /* Called before fork or exec - write out profile information gathered so 78 far and reset it to zero. This avoids duplication or loss of the 79 profile information gathered so far. */ 80 81 void 82 __gcov_flush (void) 83 { 84 init_mx_once (); 85 __gthread_mutex_lock (&__gcov_flush_mx); 86 87 __gcov_dump_int (); 88 __gcov_reset_int (); 89 90 __gthread_mutex_unlock (&__gcov_flush_mx); 91 } 92 93 #endif /* L_gcov_flush */ 94 95 #ifdef L_gcov_reset 96 97 /* Reset all counters to zero. */ 98 99 static void 100 gcov_clear (const struct gcov_info *list) 101 { 102 const struct gcov_info *gi_ptr; 103 104 for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 105 { 106 unsigned f_ix; 107 108 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) 109 { 110 unsigned t_ix; 111 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; 112 113 if (!gfi_ptr || gfi_ptr->key != gi_ptr) 114 continue; 115 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; 116 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) 117 { 118 if (!gi_ptr->merge[t_ix]) 119 continue; 120 121 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); 122 ci_ptr++; 123 } 124 } 125 } 126 } 127 128 /* Function that can be called from application to reset counters to zero, 129 in order to collect profile in region of interest. */ 130 131 void 132 __gcov_reset_int (void) 133 { 134 struct gcov_root *root; 135 136 /* If we're compatible with the master, iterate over everything, 137 otherise just do us. */ 138 for (root = __gcov_master.version == GCOV_VERSION 139 ? __gcov_master.root : &__gcov_root; root; root = root->next) 140 { 141 gcov_clear (root->list); 142 root->dumped = 0; 143 } 144 } 145 146 ALIAS_void_fn (__gcov_reset_int, __gcov_reset); 147 148 #endif /* L_gcov_reset */ 149 150 #ifdef L_gcov_dump 151 /* Function that can be called from application to write profile collected 152 so far, in order to collect profile in region of interest. */ 153 154 void 155 __gcov_dump_int (void) 156 { 157 struct gcov_root *root; 158 159 /* If we're compatible with the master, iterate over everything, 160 otherise just do us. */ 161 for (root = __gcov_master.version == GCOV_VERSION 162 ? __gcov_master.root : &__gcov_root; root; root = root->next) 163 __gcov_dump_one (root); 164 } 165 166 ALIAS_void_fn (__gcov_dump_int, __gcov_dump); 167 168 #endif /* L_gcov_dump */ 169 170 #ifdef L_gcov_fork 171 /* A wrapper for the fork function. Flushes the accumulated profiling data, so 172 that they are not counted twice. */ 173 174 pid_t 175 __gcov_fork (void) 176 { 177 pid_t pid; 178 __gcov_flush (); 179 pid = fork (); 180 if (pid == 0) 181 __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx); 182 return pid; 183 } 184 #endif 185 186 #ifdef L_gcov_execl 187 /* A wrapper for the execl function. Flushes the accumulated 188 profiling data, so that they are not lost. */ 189 190 int 191 __gcov_execl (const char *path, char *arg, ...) 192 { 193 va_list ap, aq; 194 unsigned i, length; 195 char **args; 196 197 __gcov_flush (); 198 199 va_start (ap, arg); 200 va_copy (aq, ap); 201 202 length = 2; 203 while (va_arg (ap, char *)) 204 length++; 205 va_end (ap); 206 207 args = (char **) alloca (length * sizeof (void *)); 208 args[0] = arg; 209 for (i = 1; i < length; i++) 210 args[i] = va_arg (aq, char *); 211 va_end (aq); 212 213 return execv (path, args); 214 } 215 #endif 216 217 #ifdef L_gcov_execlp 218 /* A wrapper for the execlp function. Flushes the accumulated 219 profiling data, so that they are not lost. */ 220 221 int 222 __gcov_execlp (const char *path, char *arg, ...) 223 { 224 va_list ap, aq; 225 unsigned i, length; 226 char **args; 227 228 __gcov_flush (); 229 230 va_start (ap, arg); 231 va_copy (aq, ap); 232 233 length = 2; 234 while (va_arg (ap, char *)) 235 length++; 236 va_end (ap); 237 238 args = (char **) alloca (length * sizeof (void *)); 239 args[0] = arg; 240 for (i = 1; i < length; i++) 241 args[i] = va_arg (aq, char *); 242 va_end (aq); 243 244 return execvp (path, args); 245 } 246 #endif 247 248 #ifdef L_gcov_execle 249 /* A wrapper for the execle function. Flushes the accumulated 250 profiling data, so that they are not lost. */ 251 252 int 253 __gcov_execle (const char *path, char *arg, ...) 254 { 255 va_list ap, aq; 256 unsigned i, length; 257 char **args; 258 char **envp; 259 260 __gcov_flush (); 261 262 va_start (ap, arg); 263 va_copy (aq, ap); 264 265 length = 2; 266 while (va_arg (ap, char *)) 267 length++; 268 va_end (ap); 269 270 args = (char **) alloca (length * sizeof (void *)); 271 args[0] = arg; 272 for (i = 1; i < length; i++) 273 args[i] = va_arg (aq, char *); 274 envp = va_arg (aq, char **); 275 va_end (aq); 276 277 return execve (path, args, envp); 278 } 279 #endif 280 281 #ifdef L_gcov_execv 282 /* A wrapper for the execv function. Flushes the accumulated 283 profiling data, so that they are not lost. */ 284 285 int 286 __gcov_execv (const char *path, char *const argv[]) 287 { 288 __gcov_flush (); 289 return execv (path, argv); 290 } 291 #endif 292 293 #ifdef L_gcov_execvp 294 /* A wrapper for the execvp function. Flushes the accumulated 295 profiling data, so that they are not lost. */ 296 297 int 298 __gcov_execvp (const char *path, char *const argv[]) 299 { 300 __gcov_flush (); 301 return execvp (path, argv); 302 } 303 #endif 304 305 #ifdef L_gcov_execve 306 /* A wrapper for the execve function. Flushes the accumulated 307 profiling data, so that they are not lost. */ 308 309 int 310 __gcov_execve (const char *path, char *const argv[], char *const envp[]) 311 { 312 __gcov_flush (); 313 return execve (path, argv, envp); 314 } 315 #endif 316 #endif /* inhibit_libc */ 317