1 1.1 mrg /* Routines required for instrumenting a program. */ 2 1.1 mrg /* Compile this one with gcc. */ 3 1.1.1.11 mrg /* Copyright (C) 1989-2024 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.1.8 mrg #include "gcov-io.h" 28 1.1 mrg 29 1.1.1.10 mrg /* Return 1, if all counter values are zero, otherwise 0. */ 30 1.1.1.10 mrg 31 1.1.1.10 mrg static inline int 32 1.1.1.10 mrg are_all_counters_zero (const struct gcov_ctr_info *ci_ptr) 33 1.1.1.10 mrg { 34 1.1.1.10 mrg for (unsigned i = 0; i < ci_ptr->num; i++) 35 1.1.1.10 mrg if (ci_ptr->values[i] != 0) 36 1.1.1.10 mrg return 0; 37 1.1.1.10 mrg 38 1.1.1.10 mrg return 1; 39 1.1.1.10 mrg } 40 1.1.1.10 mrg 41 1.1 mrg #if defined(inhibit_libc) 42 1.1 mrg /* If libc and its header files are not available, provide dummy functions. */ 43 1.1 mrg 44 1.1 mrg #if defined(L_gcov) 45 1.1 mrg void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} 46 1.1 mrg #endif 47 1.1 mrg 48 1.1 mrg #else /* inhibit_libc */ 49 1.1 mrg 50 1.1 mrg #if GCOV_LOCKED 51 1.1 mrg #include <fcntl.h> 52 1.1 mrg #include <errno.h> 53 1.1 mrg #include <sys/stat.h> 54 1.1.1.10 mrg #elif GCOV_LOCKED_WITH_LOCKING 55 1.1.1.10 mrg #include <fcntl.h> 56 1.1.1.10 mrg #include <sys/locking.h> 57 1.1.1.10 mrg #include <sys/stat.h> 58 1.1.1.10 mrg #endif 59 1.1.1.10 mrg 60 1.1.1.10 mrg #if HAVE_SYS_MMAN_H 61 1.1.1.10 mrg #include <sys/mman.h> 62 1.1.1.10 mrg #endif 63 1.1.1.10 mrg 64 1.1.1.10 mrg #endif /* inhibit_libc */ 65 1.1.1.10 mrg 66 1.1.1.10 mrg #if defined(L_gcov) && !defined(inhibit_libc) 67 1.1.1.10 mrg #define NEED_L_GCOV 68 1.1 mrg #endif 69 1.1 mrg 70 1.1.1.10 mrg #if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL 71 1.1.1.10 mrg #define NEED_L_GCOV_INFO_TO_GCDA 72 1.1.1.10 mrg #endif 73 1.1 mrg 74 1.1.1.10 mrg #ifdef NEED_L_GCOV 75 1.1.1.4 mrg /* A utility function for outputting errors. */ 76 1.1 mrg static int gcov_error (const char *, ...); 77 1.1 mrg 78 1.1.1.4 mrg #if !IN_GCOV_TOOL 79 1.1.1.4 mrg static void gcov_error_exit (void); 80 1.1.1.4 mrg #endif 81 1.1.1.4 mrg 82 1.1.1.10 mrg #include "gcov-io.cc" 83 1.1 mrg 84 1.1.1.8 mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:" 85 1.1.1.8 mrg 86 1.1 mrg struct gcov_fn_buffer 87 1.1 mrg { 88 1.1 mrg struct gcov_fn_buffer *next; 89 1.1 mrg unsigned fn_ix; 90 1.1 mrg struct gcov_fn_info info; 91 1.1 mrg /* note gcov_fn_info ends in a trailing array. */ 92 1.1 mrg }; 93 1.1 mrg 94 1.1 mrg struct gcov_summary_buffer 95 1.1 mrg { 96 1.1 mrg struct gcov_summary_buffer *next; 97 1.1 mrg struct gcov_summary summary; 98 1.1 mrg }; 99 1.1 mrg 100 1.1 mrg /* A struct that bundles all the related information about the 101 1.1 mrg gcda filename. */ 102 1.1 mrg 103 1.1 mrg struct gcov_filename 104 1.1 mrg { 105 1.1 mrg char *filename; /* filename buffer */ 106 1.1 mrg int strip; /* leading chars to strip from filename */ 107 1.1.1.8 mrg char *prefix; /* prefix string */ 108 1.1 mrg }; 109 1.1 mrg 110 1.1 mrg static struct gcov_fn_buffer * 111 1.1 mrg free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer, 112 1.1 mrg unsigned limit) 113 1.1 mrg { 114 1.1 mrg struct gcov_fn_buffer *next; 115 1.1 mrg unsigned ix, n_ctr = 0; 116 1.1 mrg 117 1.1 mrg if (!buffer) 118 1.1 mrg return 0; 119 1.1 mrg next = buffer->next; 120 1.1 mrg 121 1.1 mrg for (ix = 0; ix != limit; ix++) 122 1.1 mrg if (gi_ptr->merge[ix]) 123 1.1 mrg free (buffer->info.ctrs[n_ctr++].values); 124 1.1 mrg free (buffer); 125 1.1 mrg return next; 126 1.1 mrg } 127 1.1 mrg 128 1.1 mrg static struct gcov_fn_buffer ** 129 1.1 mrg buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr, 130 1.1 mrg struct gcov_fn_buffer **end_ptr, unsigned fn_ix) 131 1.1 mrg { 132 1.1 mrg unsigned n_ctrs = 0, ix = 0; 133 1.1 mrg struct gcov_fn_buffer *fn_buffer; 134 1.1 mrg unsigned len; 135 1.1 mrg 136 1.1 mrg for (ix = GCOV_COUNTERS; ix--;) 137 1.1 mrg if (gi_ptr->merge[ix]) 138 1.1 mrg n_ctrs++; 139 1.1 mrg 140 1.1 mrg len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs; 141 1.1 mrg fn_buffer = (struct gcov_fn_buffer *) xmalloc (len); 142 1.1 mrg 143 1.1 mrg if (!fn_buffer) 144 1.1 mrg goto fail; 145 1.1 mrg 146 1.1 mrg fn_buffer->next = 0; 147 1.1 mrg fn_buffer->fn_ix = fn_ix; 148 1.1 mrg fn_buffer->info.ident = gcov_read_unsigned (); 149 1.1 mrg fn_buffer->info.lineno_checksum = gcov_read_unsigned (); 150 1.1 mrg fn_buffer->info.cfg_checksum = gcov_read_unsigned (); 151 1.1 mrg 152 1.1 mrg for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) 153 1.1 mrg { 154 1.1 mrg gcov_unsigned_t length; 155 1.1 mrg gcov_type *values; 156 1.1 mrg 157 1.1 mrg if (!gi_ptr->merge[ix]) 158 1.1 mrg continue; 159 1.1 mrg 160 1.1 mrg if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix)) 161 1.1 mrg { 162 1.1 mrg len = 0; 163 1.1 mrg goto fail; 164 1.1 mrg } 165 1.1 mrg 166 1.1 mrg length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ()); 167 1.1 mrg len = length * sizeof (gcov_type); 168 1.1 mrg values = (gcov_type *) xmalloc (len); 169 1.1 mrg if (!values) 170 1.1 mrg goto fail; 171 1.1 mrg 172 1.1 mrg fn_buffer->info.ctrs[n_ctrs].num = length; 173 1.1 mrg fn_buffer->info.ctrs[n_ctrs].values = values; 174 1.1 mrg 175 1.1 mrg while (length--) 176 1.1 mrg *values++ = gcov_read_counter (); 177 1.1 mrg n_ctrs++; 178 1.1 mrg } 179 1.1 mrg 180 1.1 mrg *end_ptr = fn_buffer; 181 1.1 mrg return &fn_buffer->next; 182 1.1 mrg 183 1.1 mrg fail: 184 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix, 185 1.1 mrg len ? "cannot allocate" : "counter mismatch", len ? len : ix); 186 1.1 mrg 187 1.1 mrg return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix); 188 1.1 mrg } 189 1.1 mrg 190 1.1.1.8 mrg /* Convert VERSION into a string description and return the it. 191 1.1.1.8 mrg BUFFER is used for storage of the string. The code should be 192 1.1.1.8 mrg aligned wit gcov-iov.c. */ 193 1.1.1.8 mrg 194 1.1.1.8 mrg static char * 195 1.1.1.8 mrg gcov_version_string (char *buffer, char version[4]) 196 1.1.1.8 mrg { 197 1.1.1.8 mrg if (version[0] < 'A' || version[0] > 'Z' 198 1.1.1.8 mrg || version[1] < '0' || version[1] > '9' 199 1.1.1.8 mrg || version[2] < '0' || version[2] > '9') 200 1.1.1.8 mrg sprintf (buffer, "(unknown)"); 201 1.1.1.8 mrg else 202 1.1 mrg { 203 1.1.1.8 mrg unsigned major = 10 * (version[0] - 'A') + (version[1] - '0'); 204 1.1.1.8 mrg unsigned minor = version[2] - '0'; 205 1.1.1.8 mrg sprintf (buffer, "%u.%u (%s)", major, minor, 206 1.1.1.8 mrg version[3] == '*' ? "release" : "experimental"); 207 1.1 mrg } 208 1.1.1.8 mrg return buffer; 209 1.1 mrg } 210 1.1 mrg 211 1.1 mrg /* Check if VERSION of the info block PTR matches libgcov one. 212 1.1 mrg Return 1 on success, or zero in case of versions mismatch. 213 1.1 mrg If FILENAME is not NULL, its value used for reporting purposes 214 1.1 mrg instead of value from the info block. */ 215 1.1 mrg 216 1.1 mrg static int 217 1.1 mrg gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, 218 1.1 mrg const char *filename) 219 1.1 mrg { 220 1.1 mrg if (version != GCOV_VERSION) 221 1.1 mrg { 222 1.1 mrg char v[4], e[4]; 223 1.1.1.10 mrg char ver_string[128], expected_string[128]; 224 1.1 mrg 225 1.1 mrg GCOV_UNSIGNED2STRING (v, version); 226 1.1 mrg GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 227 1.1 mrg 228 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) " 229 1.1.1.8 mrg "got %s (%.4s)\n", 230 1.1.1.8 mrg filename? filename : ptr->filename, 231 1.1.1.8 mrg gcov_version_string (expected_string, e), e, 232 1.1.1.10 mrg gcov_version_string (ver_string, v), v); 233 1.1 mrg return 0; 234 1.1 mrg } 235 1.1 mrg return 1; 236 1.1 mrg } 237 1.1 mrg 238 1.1 mrg /* buffer for the fn_data from another program. */ 239 1.1 mrg static struct gcov_fn_buffer *fn_buffer; 240 1.1 mrg 241 1.1 mrg /* Including system dependent components. */ 242 1.1 mrg #include "libgcov-driver-system.c" 243 1.1 mrg 244 1.1 mrg /* This function merges counters in GI_PTR to an existing gcda file. 245 1.1 mrg Return 0 on success. 246 1.1 mrg Return -1 on error. In this case, caller will goto read_fatal. */ 247 1.1 mrg 248 1.1 mrg static int 249 1.1 mrg merge_one_data (const char *filename, 250 1.1 mrg struct gcov_info *gi_ptr, 251 1.1.1.8 mrg struct gcov_summary *summary) 252 1.1 mrg { 253 1.1 mrg gcov_unsigned_t tag, length; 254 1.1 mrg unsigned t_ix; 255 1.1.1.8 mrg int f_ix = -1; 256 1.1 mrg int error = 0; 257 1.1 mrg struct gcov_fn_buffer **fn_tail = &fn_buffer; 258 1.1 mrg 259 1.1 mrg length = gcov_read_unsigned (); 260 1.1 mrg if (!gcov_version (gi_ptr, length, filename)) 261 1.1 mrg return -1; 262 1.1 mrg 263 1.1.1.10 mrg /* Skip timestamp. */ 264 1.1.1.10 mrg gcov_read_unsigned (); 265 1.1.1.10 mrg 266 1.1 mrg length = gcov_read_unsigned (); 267 1.1.1.10 mrg if (length != gi_ptr->checksum) 268 1.1 mrg { 269 1.1.1.8 mrg /* Read from a different compilation. Overwrite the file. */ 270 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data " 271 1.1.1.10 mrg "with a different checksum\n", filename); 272 1.1.1.8 mrg return 0; 273 1.1 mrg } 274 1.1 mrg 275 1.1.1.8 mrg tag = gcov_read_unsigned (); 276 1.1.1.8 mrg if (tag != GCOV_TAG_OBJECT_SUMMARY) 277 1.1.1.8 mrg goto read_mismatch; 278 1.1.1.8 mrg length = gcov_read_unsigned (); 279 1.1.1.8 mrg gcc_assert (length > 0); 280 1.1.1.8 mrg gcov_read_summary (summary); 281 1.1.1.8 mrg 282 1.1.1.8 mrg tag = gcov_read_unsigned (); 283 1.1 mrg /* Merge execution counts for each function. */ 284 1.1 mrg for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; 285 1.1 mrg f_ix++, tag = gcov_read_unsigned ()) 286 1.1 mrg { 287 1.1 mrg const struct gcov_ctr_info *ci_ptr; 288 1.1 mrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; 289 1.1 mrg 290 1.1 mrg if (tag != GCOV_TAG_FUNCTION) 291 1.1 mrg goto read_mismatch; 292 1.1 mrg 293 1.1 mrg length = gcov_read_unsigned (); 294 1.1 mrg if (!length) 295 1.1 mrg /* This function did not appear in the other program. 296 1.1 mrg We have nothing to merge. */ 297 1.1 mrg continue; 298 1.1 mrg 299 1.1 mrg if (length != GCOV_TAG_FUNCTION_LENGTH) 300 1.1 mrg goto read_mismatch; 301 1.1 mrg 302 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gi_ptr) 303 1.1 mrg { 304 1.1 mrg /* This function appears in the other program. We 305 1.1 mrg need to buffer the information in order to write 306 1.1 mrg it back out -- we'll be inserting data before 307 1.1 mrg this point, so cannot simply keep the data in the 308 1.1 mrg file. */ 309 1.1 mrg fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix); 310 1.1 mrg if (!fn_tail) 311 1.1 mrg goto read_mismatch; 312 1.1 mrg continue; 313 1.1 mrg } 314 1.1 mrg 315 1.1 mrg length = gcov_read_unsigned (); 316 1.1 mrg if (length != gfi_ptr->ident) 317 1.1 mrg goto read_mismatch; 318 1.1 mrg 319 1.1 mrg length = gcov_read_unsigned (); 320 1.1 mrg if (length != gfi_ptr->lineno_checksum) 321 1.1 mrg goto read_mismatch; 322 1.1 mrg 323 1.1 mrg length = gcov_read_unsigned (); 324 1.1 mrg if (length != gfi_ptr->cfg_checksum) 325 1.1 mrg goto read_mismatch; 326 1.1 mrg 327 1.1 mrg ci_ptr = gfi_ptr->ctrs; 328 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 329 1.1 mrg { 330 1.1 mrg gcov_merge_fn merge = gi_ptr->merge[t_ix]; 331 1.1 mrg 332 1.1 mrg if (!merge) 333 1.1 mrg continue; 334 1.1 mrg 335 1.1.1.10 mrg tag = gcov_read_unsigned (); 336 1.1.1.10 mrg int read_length = (int)gcov_read_unsigned (); 337 1.1.1.10 mrg length = abs (read_length); 338 1.1.1.10 mrg if (tag != GCOV_TAG_FOR_COUNTER (t_ix) 339 1.1.1.10 mrg || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num) 340 1.1.1.10 mrg && t_ix != GCOV_COUNTER_V_TOPN 341 1.1.1.10 mrg && t_ix != GCOV_COUNTER_V_INDIR)) 342 1.1.1.10 mrg goto read_mismatch; 343 1.1.1.10 mrg /* Merging with all zero counters does not make sense. */ 344 1.1.1.10 mrg if (read_length > 0) 345 1.1.1.10 mrg (*merge) (ci_ptr->values, ci_ptr->num); 346 1.1.1.10 mrg ci_ptr++; 347 1.1.1.10 mrg } 348 1.1 mrg if ((error = gcov_is_error ())) 349 1.1.1.10 mrg goto read_error; 350 1.1 mrg } 351 1.1 mrg 352 1.1 mrg if (tag) 353 1.1 mrg { 354 1.1 mrg read_mismatch:; 355 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n", 356 1.1 mrg filename, f_ix >= 0 ? "function" : "summary", 357 1.1 mrg f_ix < 0 ? -1 - f_ix : f_ix); 358 1.1 mrg return -1; 359 1.1 mrg } 360 1.1 mrg return 0; 361 1.1 mrg 362 1.1 mrg read_error: 363 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename, 364 1.1 mrg error < 0 ? "Overflow": "Error"); 365 1.1 mrg return -1; 366 1.1 mrg } 367 1.1 mrg 368 1.1.1.10 mrg /* Write the DATA of LENGTH characters to the gcov file. */ 369 1.1.1.10 mrg 370 1.1.1.10 mrg static void 371 1.1.1.10 mrg gcov_dump_handler (const void *data, 372 1.1.1.10 mrg unsigned length, 373 1.1.1.10 mrg void *arg ATTRIBUTE_UNUSED) 374 1.1.1.10 mrg { 375 1.1.1.10 mrg gcov_write (data, length); 376 1.1.1.10 mrg } 377 1.1.1.10 mrg 378 1.1.1.10 mrg /* Allocate SIZE characters and return the address of the allocated memory. */ 379 1.1.1.10 mrg 380 1.1.1.10 mrg static void * 381 1.1.1.10 mrg gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED) 382 1.1.1.10 mrg { 383 1.1.1.10 mrg return xmalloc (size); 384 1.1.1.10 mrg } 385 1.1.1.10 mrg #endif /* NEED_L_GCOV */ 386 1.1.1.10 mrg 387 1.1.1.10 mrg #if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA) 388 1.1.1.10 mrg /* Dump the WORD using the DUMP handler called with ARG. */ 389 1.1.1.10 mrg 390 1.1.1.10 mrg static inline void 391 1.1.1.10 mrg dump_unsigned (gcov_unsigned_t word, 392 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *), 393 1.1.1.10 mrg void *arg) 394 1.1.1.10 mrg { 395 1.1.1.10 mrg (*dump_fn) (&word, sizeof (word), arg); 396 1.1.1.10 mrg } 397 1.1.1.10 mrg 398 1.1.1.10 mrg /* Dump the COUNTER using the DUMP handler called with ARG. */ 399 1.1.1.10 mrg 400 1.1.1.10 mrg static inline void 401 1.1.1.10 mrg dump_counter (gcov_type counter, 402 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *), 403 1.1.1.10 mrg void *arg) 404 1.1.1.10 mrg { 405 1.1.1.10 mrg dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg); 406 1.1.1.10 mrg 407 1.1.1.10 mrg if (sizeof (counter) > sizeof (gcov_unsigned_t)) 408 1.1.1.10 mrg dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg); 409 1.1.1.10 mrg else 410 1.1.1.10 mrg dump_unsigned (0, dump_fn, arg); 411 1.1.1.10 mrg } 412 1.1.1.10 mrg 413 1.1.1.11 mrg /* Dump the STRING using the DUMP handler called with ARG. */ 414 1.1.1.11 mrg 415 1.1.1.11 mrg static inline void 416 1.1.1.11 mrg ATTRIBUTE_UNUSED 417 1.1.1.11 mrg dump_string (const char *string, 418 1.1.1.11 mrg void (*dump_fn) (const void *, unsigned, void *), 419 1.1.1.11 mrg void *arg) 420 1.1.1.11 mrg { 421 1.1.1.11 mrg unsigned length = 0; 422 1.1.1.11 mrg 423 1.1.1.11 mrg if (string) 424 1.1.1.11 mrg length = strlen (string) + 1; 425 1.1.1.11 mrg 426 1.1.1.11 mrg dump_unsigned (length, dump_fn, arg); 427 1.1.1.11 mrg if (string) 428 1.1.1.11 mrg (*dump_fn) (string, length, arg); 429 1.1.1.11 mrg } 430 1.1.1.11 mrg 431 1.1.1.10 mrg #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) 432 1.1.1.10 mrg 433 1.1.1.10 mrg /* Store all TOP N counters where each has a dynamic length. */ 434 1.1.1.10 mrg 435 1.1.1.10 mrg static void 436 1.1.1.10 mrg write_topn_counters (const struct gcov_ctr_info *ci_ptr, 437 1.1.1.10 mrg unsigned t_ix, 438 1.1.1.10 mrg gcov_unsigned_t n_counts, 439 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *), 440 1.1.1.10 mrg void *(*allocate_fn)(unsigned, void *), 441 1.1.1.10 mrg void *arg) 442 1.1.1.10 mrg { 443 1.1.1.10 mrg unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS; 444 1.1.1.10 mrg gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0); 445 1.1.1.10 mrg 446 1.1.1.10 mrg /* It can happen in a multi-threaded environment that number of counters is 447 1.1.1.10 mrg different from the size of the corresponding linked lists. */ 448 1.1.1.10 mrg #define LIST_SIZE_MIN_LENGTH 4 * 1024 449 1.1.1.10 mrg 450 1.1.1.10 mrg static unsigned *list_sizes = NULL; 451 1.1.1.10 mrg static unsigned list_size_length = 0; 452 1.1.1.10 mrg 453 1.1.1.10 mrg if (list_sizes == NULL || counters > list_size_length) 454 1.1.1.10 mrg { 455 1.1.1.10 mrg list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters); 456 1.1.1.10 mrg #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H 457 1.1.1.10 mrg list_sizes 458 1.1.1.10 mrg = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned)); 459 1.1.1.10 mrg #endif 460 1.1.1.10 mrg 461 1.1.1.10 mrg /* Malloc fallback. */ 462 1.1.1.10 mrg if (list_sizes == NULL) 463 1.1.1.10 mrg list_sizes = 464 1.1.1.10 mrg (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned), 465 1.1.1.10 mrg arg); 466 1.1.1.10 mrg } 467 1.1.1.10 mrg 468 1.1.1.10 mrg unsigned pair_total = 0; 469 1.1.1.10 mrg 470 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++) 471 1.1.1.10 mrg { 472 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]; 473 1.1.1.10 mrg unsigned sizes = 0; 474 1.1.1.10 mrg 475 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start; 476 1.1.1.10 mrg node != NULL; node = node->next) 477 1.1.1.10 mrg ++sizes; 478 1.1.1.10 mrg 479 1.1.1.10 mrg pair_total += sizes; 480 1.1.1.10 mrg list_sizes[i] = sizes; 481 1.1.1.10 mrg } 482 1.1.1.10 mrg 483 1.1.1.10 mrg unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total; 484 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg), 485 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, arg); 486 1.1.1.10 mrg 487 1.1.1.10 mrg for (unsigned i = 0; i < counters; i++) 488 1.1.1.10 mrg { 489 1.1.1.10 mrg dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump_fn, arg); 490 1.1.1.10 mrg dump_counter (list_sizes[i], dump_fn, arg); 491 1.1.1.10 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]; 492 1.1.1.10 mrg 493 1.1.1.10 mrg unsigned j = 0; 494 1.1.1.10 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start; 495 1.1.1.10 mrg j < list_sizes[i]; node = node->next, j++) 496 1.1.1.10 mrg { 497 1.1.1.10 mrg dump_counter (node->value, dump_fn, arg); 498 1.1.1.10 mrg dump_counter (node->count, dump_fn, arg); 499 1.1.1.10 mrg } 500 1.1.1.10 mrg } 501 1.1.1.10 mrg } 502 1.1.1.10 mrg 503 1.1 mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In 504 1.1 mrg the case of appending to an existing file, SUMMARY_POS will be non-zero. 505 1.1 mrg We will write the file starting from SUMMAY_POS. */ 506 1.1 mrg 507 1.1 mrg static void 508 1.1 mrg write_one_data (const struct gcov_info *gi_ptr, 509 1.1.1.10 mrg const struct gcov_summary *prg_p ATTRIBUTE_UNUSED, 510 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *), 511 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *), 512 1.1.1.10 mrg void *arg) 513 1.1 mrg { 514 1.1 mrg unsigned f_ix; 515 1.1 mrg 516 1.1.1.10 mrg dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg); 517 1.1.1.10 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg); 518 1.1.1.10 mrg dump_unsigned (gi_ptr->stamp, dump_fn, arg); 519 1.1.1.10 mrg dump_unsigned (gi_ptr->checksum, dump_fn, arg); 520 1.1 mrg 521 1.1.1.10 mrg #ifdef NEED_L_GCOV 522 1.1 mrg /* Generate whole program statistics. */ 523 1.1.1.11 mrg gcov_write_object_summary (prg_p); 524 1.1.1.10 mrg #endif 525 1.1 mrg 526 1.1 mrg /* Write execution counts for each function. */ 527 1.1 mrg for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) 528 1.1 mrg { 529 1.1.1.10 mrg #ifdef NEED_L_GCOV 530 1.1 mrg unsigned buffered = 0; 531 1.1.1.10 mrg #endif 532 1.1 mrg const struct gcov_fn_info *gfi_ptr; 533 1.1 mrg const struct gcov_ctr_info *ci_ptr; 534 1.1 mrg gcov_unsigned_t length; 535 1.1 mrg unsigned t_ix; 536 1.1 mrg 537 1.1.1.10 mrg #ifdef NEED_L_GCOV 538 1.1 mrg if (fn_buffer && fn_buffer->fn_ix == f_ix) 539 1.1 mrg { 540 1.1 mrg /* Buffered data from another program. */ 541 1.1 mrg buffered = 1; 542 1.1 mrg gfi_ptr = &fn_buffer->info; 543 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH; 544 1.1 mrg } 545 1.1 mrg else 546 1.1.1.10 mrg #endif 547 1.1 mrg { 548 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix]; 549 1.1 mrg if (gfi_ptr && gfi_ptr->key == gi_ptr) 550 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH; 551 1.1 mrg else 552 1.1 mrg length = 0; 553 1.1 mrg } 554 1.1 mrg 555 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FUNCTION, dump_fn, arg); 556 1.1.1.10 mrg dump_unsigned (length, dump_fn, arg); 557 1.1 mrg if (!length) 558 1.1 mrg continue; 559 1.1 mrg 560 1.1.1.10 mrg dump_unsigned (gfi_ptr->ident, dump_fn, arg); 561 1.1.1.10 mrg dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg); 562 1.1.1.10 mrg dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg); 563 1.1 mrg 564 1.1 mrg ci_ptr = gfi_ptr->ctrs; 565 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 566 1.1 mrg { 567 1.1.1.10 mrg gcov_position_t n_counts; 568 1.1 mrg 569 1.1.1.10 mrg if (!gi_ptr->merge[t_ix]) 570 1.1.1.10 mrg continue; 571 1.1 mrg 572 1.1.1.10 mrg n_counts = ci_ptr->num; 573 1.1.1.10 mrg 574 1.1.1.10 mrg if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR) 575 1.1.1.10 mrg write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn, 576 1.1.1.10 mrg arg); 577 1.1.1.10 mrg else 578 1.1.1.10 mrg { 579 1.1.1.10 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg); 580 1.1.1.10 mrg if (are_all_counters_zero (ci_ptr)) 581 1.1.1.10 mrg /* Do not stream when all counters are zero. */ 582 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts), 583 1.1.1.10 mrg dump_fn, arg); 584 1.1.1.10 mrg else 585 1.1.1.10 mrg { 586 1.1.1.10 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts), 587 1.1.1.10 mrg dump_fn, arg); 588 1.1.1.10 mrg for (unsigned i = 0; i < n_counts; i++) 589 1.1.1.10 mrg dump_counter (ci_ptr->values[i], dump_fn, arg); 590 1.1.1.10 mrg } 591 1.1.1.10 mrg } 592 1.1.1.10 mrg 593 1.1.1.10 mrg ci_ptr++; 594 1.1.1.10 mrg } 595 1.1.1.10 mrg #ifdef NEED_L_GCOV 596 1.1 mrg if (buffered) 597 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 598 1.1.1.10 mrg #endif 599 1.1 mrg } 600 1.1 mrg 601 1.1.1.10 mrg dump_unsigned (0, dump_fn, arg); 602 1.1 mrg } 603 1.1.1.10 mrg #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */ 604 1.1 mrg 605 1.1.1.10 mrg #ifdef NEED_L_GCOV 606 1.1 mrg /* Dump the coverage counts for one gcov_info object. We merge with existing 607 1.1 mrg counts when possible, to avoid growing the .da files ad infinitum. We use 608 1.1 mrg this program's checksum to make sure we only accumulate whole program 609 1.1 mrg statistics to the correct summary. An object file might be embedded 610 1.1 mrg in two separate programs, and we must keep the two program 611 1.1 mrg summaries separate. */ 612 1.1 mrg 613 1.1 mrg static void 614 1.1 mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf, 615 1.1.1.10 mrg unsigned run_counted ATTRIBUTE_UNUSED, 616 1.1.1.11 mrg gcov_type run_max ATTRIBUTE_UNUSED, int mode) 617 1.1 mrg { 618 1.1.1.8 mrg struct gcov_summary summary = {}; 619 1.1 mrg int error; 620 1.1 mrg gcov_unsigned_t tag; 621 1.1 mrg fn_buffer = 0; 622 1.1 mrg 623 1.1.1.11 mrg error = gcov_exit_open_gcda_file (gi_ptr, gf, mode); 624 1.1 mrg if (error == -1) 625 1.1 mrg return; 626 1.1 mrg 627 1.1 mrg tag = gcov_read_unsigned (); 628 1.1 mrg if (tag) 629 1.1 mrg { 630 1.1 mrg /* Merge data from file. */ 631 1.1 mrg if (tag != GCOV_DATA_MAGIC) 632 1.1 mrg { 633 1.1.1.8 mrg gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n", 634 1.1.1.8 mrg gf->filename); 635 1.1 mrg goto read_fatal; 636 1.1 mrg } 637 1.1.1.8 mrg error = merge_one_data (gf->filename, gi_ptr, &summary); 638 1.1 mrg if (error == -1) 639 1.1 mrg goto read_fatal; 640 1.1 mrg } 641 1.1 mrg 642 1.1 mrg gcov_rewrite (); 643 1.1 mrg 644 1.1.1.10 mrg #if !IN_GCOV_TOOL 645 1.1.1.10 mrg if (!run_counted) 646 1.1.1.10 mrg { 647 1.1.1.10 mrg summary.runs++; 648 1.1.1.10 mrg summary.sum_max += run_max; 649 1.1.1.10 mrg } 650 1.1.1.10 mrg #else 651 1.1.1.10 mrg summary = gi_ptr->summary; 652 1.1.1.10 mrg #endif 653 1.1 mrg 654 1.1.1.10 mrg write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler, 655 1.1.1.10 mrg NULL); 656 1.1 mrg /* fall through */ 657 1.1 mrg 658 1.1 mrg read_fatal:; 659 1.1 mrg while (fn_buffer) 660 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 661 1.1 mrg 662 1.1 mrg if ((error = gcov_close ())) 663 1.1.1.10 mrg gcov_error ((error < 0 ? GCOV_PROF_PREFIX "Overflow writing\n" 664 1.1.1.10 mrg : GCOV_PROF_PREFIX "Error writing\n"), gf->filename); 665 1.1 mrg } 666 1.1 mrg 667 1.1 mrg 668 1.1 mrg /* Dump all the coverage counts for the program. It first computes program 669 1.1 mrg summary and then traverses gcov_list list and dumps the gcov_info 670 1.1.1.11 mrg objects one by one. Use MODE to open files. */ 671 1.1 mrg 672 1.1 mrg #if !IN_GCOV_TOOL 673 1.1 mrg static 674 1.1 mrg #endif 675 1.1 mrg void 676 1.1.1.11 mrg gcov_do_dump (struct gcov_info *list, int run_counted, int mode) 677 1.1 mrg { 678 1.1 mrg struct gcov_info *gi_ptr; 679 1.1 mrg struct gcov_filename gf; 680 1.1 mrg 681 1.1.1.8 mrg /* Compute run_max of this program run. */ 682 1.1.1.8 mrg gcov_type run_max = 0; 683 1.1.1.8 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 684 1.1.1.8 mrg for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) 685 1.1.1.8 mrg { 686 1.1.1.8 mrg const struct gcov_ctr_info *cinfo 687 1.1.1.8 mrg = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS]; 688 1.1.1.8 mrg 689 1.1.1.8 mrg for (unsigned i = 0; i < cinfo->num; i++) 690 1.1.1.8 mrg if (run_max < cinfo->values[i]) 691 1.1.1.8 mrg run_max = cinfo->values[i]; 692 1.1.1.8 mrg } 693 1.1 mrg 694 1.1 mrg allocate_filename_struct (&gf); 695 1.1 mrg 696 1.1 mrg /* Now merge each file. */ 697 1.1 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 698 1.1.1.8 mrg { 699 1.1.1.11 mrg dump_one_gcov (gi_ptr, &gf, run_counted, run_max, mode); 700 1.1.1.8 mrg free (gf.filename); 701 1.1.1.8 mrg } 702 1.1 mrg 703 1.1.1.8 mrg free (gf.prefix); 704 1.1 mrg } 705 1.1 mrg 706 1.1.1.2 mrg #if IN_GCOV_TOOL 707 1.1.1.2 mrg const char * 708 1.1.1.2 mrg __attribute__ ((unused)) 709 1.1.1.2 mrg gcov_get_filename (struct gcov_info *list) 710 1.1.1.2 mrg { 711 1.1.1.2 mrg return list->filename; 712 1.1.1.2 mrg } 713 1.1.1.2 mrg #endif 714 1.1.1.2 mrg 715 1.1 mrg #if !IN_GCOV_TOOL 716 1.1 mrg void 717 1.1 mrg __gcov_dump_one (struct gcov_root *root) 718 1.1 mrg { 719 1.1 mrg if (root->dumped) 720 1.1 mrg return; 721 1.1 mrg 722 1.1.1.11 mrg gcov_do_dump (root->list, root->run_counted, 0); 723 1.1 mrg 724 1.1 mrg root->dumped = 1; 725 1.1 mrg root->run_counted = 1; 726 1.1 mrg } 727 1.1 mrg 728 1.1 mrg /* Per-dynamic-object gcov state. */ 729 1.1 mrg struct gcov_root __gcov_root; 730 1.1 mrg 731 1.1 mrg /* Exactly one of these will be live in the process image. */ 732 1.1 mrg struct gcov_master __gcov_master = 733 1.1 mrg {GCOV_VERSION, 0}; 734 1.1 mrg 735 1.1.1.10 mrg /* Dynamic pool for gcov_kvp structures. */ 736 1.1.1.10 mrg struct gcov_kvp *__gcov_kvp_dynamic_pool; 737 1.1.1.10 mrg 738 1.1.1.10 mrg /* Index into __gcov_kvp_dynamic_pool array. */ 739 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_index; 740 1.1.1.10 mrg 741 1.1.1.10 mrg /* Size of _gcov_kvp_dynamic_pool array. */ 742 1.1.1.10 mrg unsigned __gcov_kvp_dynamic_pool_size; 743 1.1.1.10 mrg 744 1.1.1.4 mrg void 745 1.1.1.4 mrg __gcov_exit (void) 746 1.1 mrg { 747 1.1 mrg __gcov_dump_one (&__gcov_root); 748 1.1 mrg if (__gcov_root.next) 749 1.1 mrg __gcov_root.next->prev = __gcov_root.prev; 750 1.1 mrg if (__gcov_root.prev) 751 1.1 mrg __gcov_root.prev->next = __gcov_root.next; 752 1.1 mrg else 753 1.1 mrg __gcov_master.root = __gcov_root.next; 754 1.1.1.4 mrg 755 1.1.1.4 mrg gcov_error_exit (); 756 1.1 mrg } 757 1.1 mrg 758 1.1 mrg /* Add a new object file onto the bb chain. Invoked automatically 759 1.1 mrg when running an object file's global ctors. */ 760 1.1 mrg 761 1.1 mrg void 762 1.1 mrg __gcov_init (struct gcov_info *info) 763 1.1 mrg { 764 1.1 mrg if (!info->version || !info->n_functions) 765 1.1 mrg return; 766 1.1 mrg if (gcov_version (info, info->version, 0)) 767 1.1 mrg { 768 1.1 mrg if (!__gcov_root.list) 769 1.1 mrg { 770 1.1 mrg /* Add to master list and at exit function. */ 771 1.1 mrg if (gcov_version (NULL, __gcov_master.version, "<master>")) 772 1.1 mrg { 773 1.1 mrg __gcov_root.next = __gcov_master.root; 774 1.1 mrg if (__gcov_master.root) 775 1.1 mrg __gcov_master.root->prev = &__gcov_root; 776 1.1 mrg __gcov_master.root = &__gcov_root; 777 1.1 mrg } 778 1.1 mrg } 779 1.1 mrg 780 1.1 mrg info->next = __gcov_root.list; 781 1.1 mrg __gcov_root.list = info; 782 1.1 mrg } 783 1.1 mrg } 784 1.1 mrg #endif /* !IN_GCOV_TOOL */ 785 1.1.1.10 mrg #endif /* NEED_L_GCOV */ 786 1.1.1.10 mrg 787 1.1.1.10 mrg #ifdef NEED_L_GCOV_INFO_TO_GCDA 788 1.1.1.10 mrg /* Convert the gcov info to a gcda data stream. It is intended for 789 1.1.1.11 mrg freestanding environments which do not support the C library file I/O. */ 790 1.1.1.10 mrg 791 1.1.1.10 mrg void 792 1.1.1.10 mrg __gcov_info_to_gcda (const struct gcov_info *gi_ptr, 793 1.1.1.10 mrg void (*filename_fn) (const char *, void *), 794 1.1.1.10 mrg void (*dump_fn) (const void *, unsigned, void *), 795 1.1.1.10 mrg void *(*allocate_fn) (unsigned, void *), 796 1.1.1.10 mrg void *arg) 797 1.1.1.10 mrg { 798 1.1.1.10 mrg (*filename_fn) (gi_ptr->filename, arg); 799 1.1.1.10 mrg write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg); 800 1.1.1.10 mrg } 801 1.1.1.11 mrg 802 1.1.1.11 mrg /* Convert the filename to a gcfn data stream. It is intended for 803 1.1.1.11 mrg freestanding environments which do not support the C library file I/O. */ 804 1.1.1.11 mrg 805 1.1.1.11 mrg void 806 1.1.1.11 mrg __gcov_filename_to_gcfn (const char *filename, 807 1.1.1.11 mrg void (*dump_fn) (const void *, unsigned, void *), 808 1.1.1.11 mrg void *arg) 809 1.1.1.11 mrg { 810 1.1.1.11 mrg dump_unsigned (GCOV_FILENAME_MAGIC, dump_fn, arg); 811 1.1.1.11 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg); 812 1.1.1.11 mrg dump_string (filename, dump_fn, arg); 813 1.1.1.11 mrg } 814 1.1.1.10 mrg #endif /* NEED_L_GCOV_INFO_TO_GCDA */ 815