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.5 mrg #include "gcov-io.h" 28 1.1 mrg 29 1.7 mrg /* Return 1, if all counter values are zero, otherwise 0. */ 30 1.7 mrg 31 1.7 mrg static inline int 32 1.7 mrg are_all_counters_zero (const struct gcov_ctr_info *ci_ptr) 33 1.7 mrg { 34 1.7 mrg for (unsigned i = 0; i < ci_ptr->num; i++) 35 1.7 mrg if (ci_ptr->values[i] != 0) 36 1.7 mrg return 0; 37 1.7 mrg 38 1.7 mrg return 1; 39 1.7 mrg } 40 1.7 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.7 mrg #elif GCOV_LOCKED_WITH_LOCKING 55 1.7 mrg #include <fcntl.h> 56 1.7 mrg #include <sys/locking.h> 57 1.7 mrg #include <sys/stat.h> 58 1.7 mrg #endif 59 1.7 mrg 60 1.7 mrg #if HAVE_SYS_MMAN_H 61 1.7 mrg #include <sys/mman.h> 62 1.7 mrg #endif 63 1.7 mrg 64 1.7 mrg #endif /* inhibit_libc */ 65 1.7 mrg 66 1.7 mrg #if defined(L_gcov) && !defined(inhibit_libc) 67 1.7 mrg #define NEED_L_GCOV 68 1.1 mrg #endif 69 1.1 mrg 70 1.7 mrg #if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL 71 1.7 mrg #define NEED_L_GCOV_INFO_TO_GCDA 72 1.7 mrg #endif 73 1.1 mrg 74 1.7 mrg #ifdef NEED_L_GCOV 75 1.3 mrg /* A utility function for outputting errors. */ 76 1.1 mrg static int gcov_error (const char *, ...); 77 1.1 mrg 78 1.3 mrg #if !IN_GCOV_TOOL 79 1.3 mrg static void gcov_error_exit (void); 80 1.3 mrg #endif 81 1.3 mrg 82 1.7 mrg #include "gcov-io.cc" 83 1.1 mrg 84 1.5 mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:" 85 1.5 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.5 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.5 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.5 mrg /* Convert VERSION into a string description and return the it. 191 1.5 mrg BUFFER is used for storage of the string. The code should be 192 1.5 mrg aligned wit gcov-iov.c. */ 193 1.5 mrg 194 1.5 mrg static char * 195 1.5 mrg gcov_version_string (char *buffer, char version[4]) 196 1.5 mrg { 197 1.5 mrg if (version[0] < 'A' || version[0] > 'Z' 198 1.5 mrg || version[1] < '0' || version[1] > '9' 199 1.5 mrg || version[2] < '0' || version[2] > '9') 200 1.5 mrg sprintf (buffer, "(unknown)"); 201 1.5 mrg else 202 1.1 mrg { 203 1.5 mrg unsigned major = 10 * (version[0] - 'A') + (version[1] - '0'); 204 1.5 mrg unsigned minor = version[2] - '0'; 205 1.5 mrg sprintf (buffer, "%u.%u (%s)", major, minor, 206 1.5 mrg version[3] == '*' ? "release" : "experimental"); 207 1.1 mrg } 208 1.5 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.7 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.5 mrg gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) " 229 1.5 mrg "got %s (%.4s)\n", 230 1.5 mrg filename? filename : ptr->filename, 231 1.5 mrg gcov_version_string (expected_string, e), e, 232 1.7 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.5 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.5 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.7 mrg /* Skip timestamp. */ 264 1.7 mrg gcov_read_unsigned (); 265 1.7 mrg 266 1.1 mrg length = gcov_read_unsigned (); 267 1.7 mrg if (length != gi_ptr->checksum) 268 1.1 mrg { 269 1.5 mrg /* Read from a different compilation. Overwrite the file. */ 270 1.5 mrg gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data " 271 1.7 mrg "with a different checksum\n", filename); 272 1.5 mrg return 0; 273 1.5 mrg } 274 1.1 mrg 275 1.5 mrg tag = gcov_read_unsigned (); 276 1.5 mrg if (tag != GCOV_TAG_OBJECT_SUMMARY) 277 1.5 mrg goto read_mismatch; 278 1.5 mrg length = gcov_read_unsigned (); 279 1.5 mrg gcc_assert (length > 0); 280 1.5 mrg gcov_read_summary (summary); 281 1.1 mrg 282 1.5 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.7 mrg tag = gcov_read_unsigned (); 336 1.7 mrg int read_length = (int)gcov_read_unsigned (); 337 1.7 mrg length = abs (read_length); 338 1.7 mrg if (tag != GCOV_TAG_FOR_COUNTER (t_ix) 339 1.7 mrg || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num) 340 1.7 mrg && t_ix != GCOV_COUNTER_V_TOPN 341 1.7 mrg && t_ix != GCOV_COUNTER_V_INDIR)) 342 1.7 mrg goto read_mismatch; 343 1.7 mrg /* Merging with all zero counters does not make sense. */ 344 1.7 mrg if (read_length > 0) 345 1.7 mrg (*merge) (ci_ptr->values, ci_ptr->num); 346 1.7 mrg ci_ptr++; 347 1.7 mrg } 348 1.1 mrg if ((error = gcov_is_error ())) 349 1.7 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.5 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.5 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.7 mrg /* Write the DATA of LENGTH characters to the gcov file. */ 369 1.7 mrg 370 1.7 mrg static void 371 1.7 mrg gcov_dump_handler (const void *data, 372 1.7 mrg unsigned length, 373 1.7 mrg void *arg ATTRIBUTE_UNUSED) 374 1.7 mrg { 375 1.7 mrg gcov_write (data, length); 376 1.7 mrg } 377 1.7 mrg 378 1.7 mrg /* Allocate SIZE characters and return the address of the allocated memory. */ 379 1.7 mrg 380 1.7 mrg static void * 381 1.7 mrg gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED) 382 1.7 mrg { 383 1.7 mrg return xmalloc (size); 384 1.7 mrg } 385 1.7 mrg #endif /* NEED_L_GCOV */ 386 1.7 mrg 387 1.7 mrg #if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA) 388 1.7 mrg /* Dump the WORD using the DUMP handler called with ARG. */ 389 1.7 mrg 390 1.7 mrg static inline void 391 1.7 mrg dump_unsigned (gcov_unsigned_t word, 392 1.7 mrg void (*dump_fn) (const void *, unsigned, void *), 393 1.7 mrg void *arg) 394 1.7 mrg { 395 1.7 mrg (*dump_fn) (&word, sizeof (word), arg); 396 1.7 mrg } 397 1.7 mrg 398 1.7 mrg /* Dump the COUNTER using the DUMP handler called with ARG. */ 399 1.7 mrg 400 1.7 mrg static inline void 401 1.7 mrg dump_counter (gcov_type counter, 402 1.7 mrg void (*dump_fn) (const void *, unsigned, void *), 403 1.7 mrg void *arg) 404 1.7 mrg { 405 1.7 mrg dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg); 406 1.7 mrg 407 1.7 mrg if (sizeof (counter) > sizeof (gcov_unsigned_t)) 408 1.7 mrg dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg); 409 1.7 mrg else 410 1.7 mrg dump_unsigned (0, dump_fn, arg); 411 1.7 mrg } 412 1.7 mrg 413 1.7 mrg #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) 414 1.7 mrg 415 1.7 mrg /* Store all TOP N counters where each has a dynamic length. */ 416 1.7 mrg 417 1.7 mrg static void 418 1.7 mrg write_topn_counters (const struct gcov_ctr_info *ci_ptr, 419 1.7 mrg unsigned t_ix, 420 1.7 mrg gcov_unsigned_t n_counts, 421 1.7 mrg void (*dump_fn) (const void *, unsigned, void *), 422 1.7 mrg void *(*allocate_fn)(unsigned, void *), 423 1.7 mrg void *arg) 424 1.7 mrg { 425 1.7 mrg unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS; 426 1.7 mrg gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0); 427 1.7 mrg 428 1.7 mrg /* It can happen in a multi-threaded environment that number of counters is 429 1.7 mrg different from the size of the corresponding linked lists. */ 430 1.7 mrg #define LIST_SIZE_MIN_LENGTH 4 * 1024 431 1.7 mrg 432 1.7 mrg static unsigned *list_sizes = NULL; 433 1.7 mrg static unsigned list_size_length = 0; 434 1.7 mrg 435 1.7 mrg if (list_sizes == NULL || counters > list_size_length) 436 1.7 mrg { 437 1.7 mrg list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters); 438 1.7 mrg #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H 439 1.7 mrg list_sizes 440 1.7 mrg = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned)); 441 1.7 mrg #endif 442 1.7 mrg 443 1.7 mrg /* Malloc fallback. */ 444 1.7 mrg if (list_sizes == NULL) 445 1.7 mrg list_sizes = 446 1.7 mrg (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned), 447 1.7 mrg arg); 448 1.7 mrg } 449 1.7 mrg 450 1.7 mrg unsigned pair_total = 0; 451 1.7 mrg 452 1.7 mrg for (unsigned i = 0; i < counters; i++) 453 1.7 mrg { 454 1.7 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]; 455 1.7 mrg unsigned sizes = 0; 456 1.7 mrg 457 1.7 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start; 458 1.7 mrg node != NULL; node = node->next) 459 1.7 mrg ++sizes; 460 1.7 mrg 461 1.7 mrg pair_total += sizes; 462 1.7 mrg list_sizes[i] = sizes; 463 1.7 mrg } 464 1.7 mrg 465 1.7 mrg unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total; 466 1.7 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg), 467 1.7 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, arg); 468 1.7 mrg 469 1.7 mrg for (unsigned i = 0; i < counters; i++) 470 1.7 mrg { 471 1.7 mrg dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump_fn, arg); 472 1.7 mrg dump_counter (list_sizes[i], dump_fn, arg); 473 1.7 mrg gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]; 474 1.7 mrg 475 1.7 mrg unsigned j = 0; 476 1.7 mrg for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start; 477 1.7 mrg j < list_sizes[i]; node = node->next, j++) 478 1.7 mrg { 479 1.7 mrg dump_counter (node->value, dump_fn, arg); 480 1.7 mrg dump_counter (node->count, dump_fn, arg); 481 1.7 mrg } 482 1.7 mrg } 483 1.7 mrg } 484 1.7 mrg 485 1.1 mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In 486 1.1 mrg the case of appending to an existing file, SUMMARY_POS will be non-zero. 487 1.1 mrg We will write the file starting from SUMMAY_POS. */ 488 1.1 mrg 489 1.1 mrg static void 490 1.1 mrg write_one_data (const struct gcov_info *gi_ptr, 491 1.7 mrg const struct gcov_summary *prg_p ATTRIBUTE_UNUSED, 492 1.7 mrg void (*dump_fn) (const void *, unsigned, void *), 493 1.7 mrg void *(*allocate_fn) (unsigned, void *), 494 1.7 mrg void *arg) 495 1.1 mrg { 496 1.1 mrg unsigned f_ix; 497 1.1 mrg 498 1.7 mrg dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg); 499 1.7 mrg dump_unsigned (GCOV_VERSION, dump_fn, arg); 500 1.7 mrg dump_unsigned (gi_ptr->stamp, dump_fn, arg); 501 1.7 mrg dump_unsigned (gi_ptr->checksum, dump_fn, arg); 502 1.1 mrg 503 1.7 mrg #ifdef NEED_L_GCOV 504 1.1 mrg /* Generate whole program statistics. */ 505 1.5 mrg gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p); 506 1.7 mrg #endif 507 1.1 mrg 508 1.1 mrg /* Write execution counts for each function. */ 509 1.1 mrg for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) 510 1.1 mrg { 511 1.7 mrg #ifdef NEED_L_GCOV 512 1.1 mrg unsigned buffered = 0; 513 1.7 mrg #endif 514 1.1 mrg const struct gcov_fn_info *gfi_ptr; 515 1.1 mrg const struct gcov_ctr_info *ci_ptr; 516 1.1 mrg gcov_unsigned_t length; 517 1.1 mrg unsigned t_ix; 518 1.1 mrg 519 1.7 mrg #ifdef NEED_L_GCOV 520 1.1 mrg if (fn_buffer && fn_buffer->fn_ix == f_ix) 521 1.1 mrg { 522 1.1 mrg /* Buffered data from another program. */ 523 1.1 mrg buffered = 1; 524 1.1 mrg gfi_ptr = &fn_buffer->info; 525 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH; 526 1.1 mrg } 527 1.1 mrg else 528 1.7 mrg #endif 529 1.1 mrg { 530 1.1 mrg gfi_ptr = gi_ptr->functions[f_ix]; 531 1.1 mrg if (gfi_ptr && gfi_ptr->key == gi_ptr) 532 1.1 mrg length = GCOV_TAG_FUNCTION_LENGTH; 533 1.1 mrg else 534 1.1 mrg length = 0; 535 1.1 mrg } 536 1.1 mrg 537 1.7 mrg dump_unsigned (GCOV_TAG_FUNCTION, dump_fn, arg); 538 1.7 mrg dump_unsigned (length, dump_fn, arg); 539 1.1 mrg if (!length) 540 1.1 mrg continue; 541 1.1 mrg 542 1.7 mrg dump_unsigned (gfi_ptr->ident, dump_fn, arg); 543 1.7 mrg dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg); 544 1.7 mrg dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg); 545 1.1 mrg 546 1.1 mrg ci_ptr = gfi_ptr->ctrs; 547 1.1 mrg for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 548 1.1 mrg { 549 1.7 mrg gcov_position_t n_counts; 550 1.1 mrg 551 1.7 mrg if (!gi_ptr->merge[t_ix]) 552 1.7 mrg continue; 553 1.7 mrg 554 1.7 mrg n_counts = ci_ptr->num; 555 1.7 mrg 556 1.7 mrg if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR) 557 1.7 mrg write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn, 558 1.7 mrg arg); 559 1.7 mrg else 560 1.7 mrg { 561 1.7 mrg dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg); 562 1.7 mrg if (are_all_counters_zero (ci_ptr)) 563 1.7 mrg /* Do not stream when all counters are zero. */ 564 1.7 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts), 565 1.7 mrg dump_fn, arg); 566 1.7 mrg else 567 1.7 mrg { 568 1.7 mrg dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts), 569 1.7 mrg dump_fn, arg); 570 1.7 mrg for (unsigned i = 0; i < n_counts; i++) 571 1.7 mrg dump_counter (ci_ptr->values[i], dump_fn, arg); 572 1.7 mrg } 573 1.7 mrg } 574 1.1 mrg 575 1.7 mrg ci_ptr++; 576 1.7 mrg } 577 1.7 mrg #ifdef NEED_L_GCOV 578 1.1 mrg if (buffered) 579 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 580 1.7 mrg #endif 581 1.1 mrg } 582 1.1 mrg 583 1.7 mrg dump_unsigned (0, dump_fn, arg); 584 1.1 mrg } 585 1.7 mrg #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */ 586 1.1 mrg 587 1.7 mrg #ifdef NEED_L_GCOV 588 1.1 mrg /* Dump the coverage counts for one gcov_info object. We merge with existing 589 1.1 mrg counts when possible, to avoid growing the .da files ad infinitum. We use 590 1.1 mrg this program's checksum to make sure we only accumulate whole program 591 1.1 mrg statistics to the correct summary. An object file might be embedded 592 1.1 mrg in two separate programs, and we must keep the two program 593 1.1 mrg summaries separate. */ 594 1.1 mrg 595 1.1 mrg static void 596 1.1 mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf, 597 1.7 mrg unsigned run_counted ATTRIBUTE_UNUSED, 598 1.7 mrg gcov_type run_max ATTRIBUTE_UNUSED) 599 1.1 mrg { 600 1.5 mrg struct gcov_summary summary = {}; 601 1.1 mrg int error; 602 1.1 mrg gcov_unsigned_t tag; 603 1.1 mrg fn_buffer = 0; 604 1.1 mrg 605 1.1 mrg error = gcov_exit_open_gcda_file (gi_ptr, gf); 606 1.1 mrg if (error == -1) 607 1.1 mrg return; 608 1.1 mrg 609 1.1 mrg tag = gcov_read_unsigned (); 610 1.1 mrg if (tag) 611 1.1 mrg { 612 1.1 mrg /* Merge data from file. */ 613 1.1 mrg if (tag != GCOV_DATA_MAGIC) 614 1.1 mrg { 615 1.5 mrg gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n", 616 1.5 mrg gf->filename); 617 1.1 mrg goto read_fatal; 618 1.1 mrg } 619 1.5 mrg error = merge_one_data (gf->filename, gi_ptr, &summary); 620 1.1 mrg if (error == -1) 621 1.1 mrg goto read_fatal; 622 1.1 mrg } 623 1.1 mrg 624 1.1 mrg gcov_rewrite (); 625 1.1 mrg 626 1.7 mrg #if !IN_GCOV_TOOL 627 1.7 mrg if (!run_counted) 628 1.7 mrg { 629 1.7 mrg summary.runs++; 630 1.7 mrg summary.sum_max += run_max; 631 1.7 mrg } 632 1.7 mrg #else 633 1.7 mrg summary = gi_ptr->summary; 634 1.7 mrg #endif 635 1.1 mrg 636 1.7 mrg write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler, 637 1.7 mrg NULL); 638 1.1 mrg /* fall through */ 639 1.1 mrg 640 1.1 mrg read_fatal:; 641 1.1 mrg while (fn_buffer) 642 1.1 mrg fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 643 1.1 mrg 644 1.1 mrg if ((error = gcov_close ())) 645 1.7 mrg gcov_error ((error < 0 ? GCOV_PROF_PREFIX "Overflow writing\n" 646 1.7 mrg : GCOV_PROF_PREFIX "Error writing\n"), gf->filename); 647 1.1 mrg } 648 1.1 mrg 649 1.1 mrg 650 1.1 mrg /* Dump all the coverage counts for the program. It first computes program 651 1.1 mrg summary and then traverses gcov_list list and dumps the gcov_info 652 1.1 mrg objects one by one. */ 653 1.1 mrg 654 1.1 mrg #if !IN_GCOV_TOOL 655 1.1 mrg static 656 1.1 mrg #endif 657 1.1 mrg void 658 1.1 mrg gcov_do_dump (struct gcov_info *list, int run_counted) 659 1.1 mrg { 660 1.1 mrg struct gcov_info *gi_ptr; 661 1.1 mrg struct gcov_filename gf; 662 1.1 mrg 663 1.5 mrg /* Compute run_max of this program run. */ 664 1.5 mrg gcov_type run_max = 0; 665 1.5 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 666 1.5 mrg for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) 667 1.5 mrg { 668 1.5 mrg const struct gcov_ctr_info *cinfo 669 1.5 mrg = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS]; 670 1.5 mrg 671 1.5 mrg for (unsigned i = 0; i < cinfo->num; i++) 672 1.5 mrg if (run_max < cinfo->values[i]) 673 1.5 mrg run_max = cinfo->values[i]; 674 1.5 mrg } 675 1.1 mrg 676 1.1 mrg allocate_filename_struct (&gf); 677 1.1 mrg 678 1.1 mrg /* Now merge each file. */ 679 1.1 mrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) 680 1.5 mrg { 681 1.5 mrg dump_one_gcov (gi_ptr, &gf, run_counted, run_max); 682 1.5 mrg free (gf.filename); 683 1.5 mrg } 684 1.1 mrg 685 1.5 mrg free (gf.prefix); 686 1.1 mrg } 687 1.1 mrg 688 1.3 mrg #if IN_GCOV_TOOL 689 1.3 mrg const char * 690 1.3 mrg __attribute__ ((unused)) 691 1.3 mrg gcov_get_filename (struct gcov_info *list) 692 1.3 mrg { 693 1.3 mrg return list->filename; 694 1.3 mrg } 695 1.3 mrg #endif 696 1.3 mrg 697 1.1 mrg #if !IN_GCOV_TOOL 698 1.1 mrg void 699 1.1 mrg __gcov_dump_one (struct gcov_root *root) 700 1.1 mrg { 701 1.1 mrg if (root->dumped) 702 1.1 mrg return; 703 1.1 mrg 704 1.1 mrg gcov_do_dump (root->list, root->run_counted); 705 1.1 mrg 706 1.1 mrg root->dumped = 1; 707 1.1 mrg root->run_counted = 1; 708 1.1 mrg } 709 1.1 mrg 710 1.1 mrg /* Per-dynamic-object gcov state. */ 711 1.1 mrg struct gcov_root __gcov_root; 712 1.1 mrg 713 1.1 mrg /* Exactly one of these will be live in the process image. */ 714 1.1 mrg struct gcov_master __gcov_master = 715 1.1 mrg {GCOV_VERSION, 0}; 716 1.1 mrg 717 1.7 mrg /* Dynamic pool for gcov_kvp structures. */ 718 1.7 mrg struct gcov_kvp *__gcov_kvp_dynamic_pool; 719 1.7 mrg 720 1.7 mrg /* Index into __gcov_kvp_dynamic_pool array. */ 721 1.7 mrg unsigned __gcov_kvp_dynamic_pool_index; 722 1.7 mrg 723 1.7 mrg /* Size of _gcov_kvp_dynamic_pool array. */ 724 1.7 mrg unsigned __gcov_kvp_dynamic_pool_size; 725 1.7 mrg 726 1.3 mrg void 727 1.3 mrg __gcov_exit (void) 728 1.1 mrg { 729 1.1 mrg __gcov_dump_one (&__gcov_root); 730 1.1 mrg if (__gcov_root.next) 731 1.1 mrg __gcov_root.next->prev = __gcov_root.prev; 732 1.1 mrg if (__gcov_root.prev) 733 1.1 mrg __gcov_root.prev->next = __gcov_root.next; 734 1.1 mrg else 735 1.1 mrg __gcov_master.root = __gcov_root.next; 736 1.3 mrg 737 1.3 mrg gcov_error_exit (); 738 1.1 mrg } 739 1.1 mrg 740 1.1 mrg /* Add a new object file onto the bb chain. Invoked automatically 741 1.1 mrg when running an object file's global ctors. */ 742 1.1 mrg 743 1.1 mrg void 744 1.1 mrg __gcov_init (struct gcov_info *info) 745 1.1 mrg { 746 1.1 mrg if (!info->version || !info->n_functions) 747 1.1 mrg return; 748 1.1 mrg if (gcov_version (info, info->version, 0)) 749 1.1 mrg { 750 1.1 mrg if (!__gcov_root.list) 751 1.1 mrg { 752 1.1 mrg /* Add to master list and at exit function. */ 753 1.1 mrg if (gcov_version (NULL, __gcov_master.version, "<master>")) 754 1.1 mrg { 755 1.1 mrg __gcov_root.next = __gcov_master.root; 756 1.1 mrg if (__gcov_master.root) 757 1.1 mrg __gcov_master.root->prev = &__gcov_root; 758 1.1 mrg __gcov_master.root = &__gcov_root; 759 1.1 mrg } 760 1.1 mrg } 761 1.1 mrg 762 1.1 mrg info->next = __gcov_root.list; 763 1.1 mrg __gcov_root.list = info; 764 1.1 mrg } 765 1.1 mrg } 766 1.1 mrg #endif /* !IN_GCOV_TOOL */ 767 1.7 mrg #endif /* NEED_L_GCOV */ 768 1.7 mrg 769 1.7 mrg #ifdef NEED_L_GCOV_INFO_TO_GCDA 770 1.7 mrg /* Convert the gcov info to a gcda data stream. It is intended for 771 1.7 mrg free-standing environments which do not support the C library file I/O. */ 772 1.7 mrg 773 1.7 mrg void 774 1.7 mrg __gcov_info_to_gcda (const struct gcov_info *gi_ptr, 775 1.7 mrg void (*filename_fn) (const char *, void *), 776 1.7 mrg void (*dump_fn) (const void *, unsigned, void *), 777 1.7 mrg void *(*allocate_fn) (unsigned, void *), 778 1.7 mrg void *arg) 779 1.7 mrg { 780 1.7 mrg (*filename_fn) (gi_ptr->filename, arg); 781 1.7 mrg write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg); 782 1.7 mrg } 783 1.7 mrg #endif /* NEED_L_GCOV_INFO_TO_GCDA */ 784