1 /* File format for coverage information 2 Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007, 3 2008 Free Software Foundation, Inc. 4 Contributed by Bob Manson <manson (at) cygnus.com>. 5 Completely remangled by Nathan Sidwell <nathan (at) codesourcery.com>. 6 7 This file is part of GCC. 8 9 GCC is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free 11 Software Foundation; either version 3, or (at your option) any later 12 version. 13 14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15 WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 for more details. 18 19 Under Section 7 of GPL version 3, you are granted additional 20 permissions described in the GCC Runtime Library Exception, version 21 3.1, as published by the Free Software Foundation. 22 23 You should have received a copy of the GNU General Public License and 24 a copy of the GCC Runtime Library Exception along with this program; 25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 26 <http://www.gnu.org/licenses/>. */ 27 28 /* Routines declared in gcov-io.h. This file should be #included by 29 another source file, after having #included gcov-io.h. */ 30 31 /* Redefine these here, rather than using the ones in system.h since 32 * including system.h leads to conflicting definitions of other 33 * symbols and macros. */ 34 #undef MIN 35 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) 36 37 #if !IN_GCOV 38 static void gcov_write_block (unsigned); 39 static gcov_unsigned_t *gcov_write_words (unsigned); 40 #endif 41 static const gcov_unsigned_t *gcov_read_words (unsigned); 42 #if !IN_LIBGCOV 43 static void gcov_allocate (unsigned); 44 #endif 45 46 #ifdef __GCOV_KERNEL__ 47 struct gcov_var gcov_var ATTRIBUTE_HIDDEN; 48 #endif 49 50 static inline gcov_unsigned_t from_file (gcov_unsigned_t value) 51 { 52 #if !IN_LIBGCOV 53 if (gcov_var.endian) 54 { 55 value = (value >> 16) | (value << 16); 56 value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff); 57 } 58 #endif 59 return value; 60 } 61 62 /* Open a gcov file. NAME is the name of the file to open and MODE 63 indicates whether a new file should be created, or an existing file 64 opened. If MODE is >= 0 an existing file will be opened, if 65 possible, and if MODE is <= 0, a new file will be created. Use 66 MODE=0 to attempt to reopen an existing file and then fall back on 67 creating a new one. If MODE < 0, the file will be opened in 68 read-only mode. Otherwise it will be opened for modification. 69 Return zero on failure, >0 on opening an existing file and <0 on 70 creating a new one. */ 71 72 #ifndef __GCOV_KERNEL__ 73 GCOV_LINKAGE int 74 #if IN_LIBGCOV 75 gcov_open (const char *name) 76 #else 77 gcov_open (const char *name, int mode) 78 #endif 79 { 80 #if IN_LIBGCOV 81 const int mode = 0; 82 #endif 83 #if GCOV_LOCKED 84 struct flock s_flock; 85 int fd; 86 87 s_flock.l_whence = SEEK_SET; 88 s_flock.l_start = 0; 89 s_flock.l_len = 0; /* Until EOF. */ 90 s_flock.l_pid = getpid (); 91 #endif 92 93 gcc_assert (!gcov_var.file); 94 gcov_var.start = 0; 95 gcov_var.offset = gcov_var.length = 0; 96 gcov_var.overread = -1u; 97 gcov_var.error = 0; 98 #if !IN_LIBGCOV 99 gcov_var.endian = 0; 100 #endif 101 #if GCOV_LOCKED 102 if (mode > 0) 103 { 104 /* Read-only mode - acquire a read-lock. */ 105 s_flock.l_type = F_RDLCK; 106 fd = open (name, O_RDONLY); 107 } 108 else 109 { 110 /* Write mode - acquire a write-lock. */ 111 s_flock.l_type = F_WRLCK; 112 fd = open (name, O_RDWR | O_CREAT, 0666); 113 } 114 if (fd < 0) 115 return 0; 116 117 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) 118 continue; 119 120 gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b"); 121 122 if (!gcov_var.file) 123 { 124 close (fd); 125 return 0; 126 } 127 128 if (mode > 0) 129 gcov_var.mode = 1; 130 else if (mode == 0) 131 { 132 struct stat st; 133 134 if (fstat (fd, &st) < 0) 135 { 136 fclose (gcov_var.file); 137 gcov_var.file = 0; 138 return 0; 139 } 140 if (st.st_size != 0) 141 gcov_var.mode = 1; 142 else 143 gcov_var.mode = mode * 2 + 1; 144 } 145 else 146 gcov_var.mode = mode * 2 + 1; 147 #else 148 if (mode >= 0) 149 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b"); 150 151 if (gcov_var.file) 152 gcov_var.mode = 1; 153 else if (mode <= 0) 154 { 155 gcov_var.file = fopen (name, "w+b"); 156 if (gcov_var.file) 157 gcov_var.mode = mode * 2 + 1; 158 } 159 if (!gcov_var.file) 160 return 0; 161 #endif 162 163 setbuf (gcov_var.file, (char *)0); 164 165 return 1; 166 } 167 #else /* __GCOV_KERNEL__ */ 168 169 extern _GCOV_FILE *gcov_current_file; 170 171 GCOV_LINKAGE int 172 gcov_open (const char *name) 173 { 174 gcov_var.start = 0; 175 gcov_var.offset = gcov_var.length = 0; 176 gcov_var.overread = -1u; 177 gcov_var.error = 0; 178 gcov_var.file = gcov_current_file; 179 gcov_var.mode = 1; 180 181 return 1; 182 } 183 #endif /* __GCOV_KERNEL__ */ 184 185 /* Close the current gcov file. Flushes data to disk. Returns nonzero 186 on failure or error flag set. */ 187 188 GCOV_LINKAGE int 189 gcov_close (void) 190 { 191 if (gcov_var.file) 192 { 193 #if !IN_GCOV 194 if (gcov_var.offset && gcov_var.mode < 0) 195 gcov_write_block (gcov_var.offset); 196 #endif 197 _GCOV_fclose (gcov_var.file); 198 gcov_var.file = 0; 199 gcov_var.length = 0; 200 } 201 #if !IN_LIBGCOV 202 free (gcov_var.buffer); 203 gcov_var.alloc = 0; 204 gcov_var.buffer = 0; 205 #endif 206 gcov_var.mode = 0; 207 return gcov_var.error; 208 } 209 210 #if !IN_LIBGCOV 211 /* Modify FILENAME to a canonical form after stripping known prefixes 212 in place. It removes '/proc/self/cwd' and '/proc/self/cwd/.'. 213 Returns the in-place modified filename. */ 214 215 GCOV_LINKAGE char * 216 gcov_canonical_filename (char *filename) 217 { 218 static char cwd_dot_str[] = "/proc/self/cwd/./"; 219 int cwd_dot_len = strlen (cwd_dot_str); 220 int cwd_len = cwd_dot_len - 2; /* without trailing './' */ 221 int filename_len = strlen (filename); 222 /* delete the longer prefix first */ 223 if (0 == strncmp (filename, cwd_dot_str, cwd_dot_len)) 224 { 225 memmove (filename, filename + cwd_dot_len, filename_len - cwd_dot_len); 226 filename[filename_len - cwd_dot_len] = '\0'; 227 return filename; 228 } 229 230 if (0 == strncmp (filename, cwd_dot_str, cwd_len)) 231 { 232 memmove (filename, filename + cwd_len, filename_len - cwd_len); 233 filename[filename_len - cwd_len] = '\0'; 234 return filename; 235 } 236 return filename; 237 } 238 239 /* Read LEN words and construct load latency info LL_INFO. */ 240 241 GCOV_LINKAGE void 242 gcov_read_pmu_load_latency_info (gcov_pmu_ll_info_t *ll_info, 243 gcov_unsigned_t len ATTRIBUTE_UNUSED) 244 { 245 const char *filename; 246 ll_info->counts = gcov_read_unsigned (); 247 ll_info->self = gcov_read_unsigned (); 248 ll_info->cum = gcov_read_unsigned (); 249 ll_info->lt_10 = gcov_read_unsigned (); 250 ll_info->lt_32 = gcov_read_unsigned (); 251 ll_info->lt_64 = gcov_read_unsigned (); 252 ll_info->lt_256 = gcov_read_unsigned (); 253 ll_info->lt_1024 = gcov_read_unsigned (); 254 ll_info->gt_1024 = gcov_read_unsigned (); 255 ll_info->wself = gcov_read_unsigned (); 256 ll_info->code_addr = gcov_read_counter (); 257 ll_info->line = gcov_read_unsigned (); 258 ll_info->discriminator = gcov_read_unsigned (); 259 filename = gcov_read_string (); 260 if (filename) 261 ll_info->filename = gcov_canonical_filename (xstrdup (filename)); 262 else 263 ll_info->filename = 0; 264 } 265 266 /* Read LEN words and construct branch mispredict info BRM_INFO. */ 267 268 GCOV_LINKAGE void 269 gcov_read_pmu_branch_mispredict_info (gcov_pmu_brm_info_t *brm_info, 270 gcov_unsigned_t len ATTRIBUTE_UNUSED) 271 { 272 const char *filename; 273 brm_info->counts = gcov_read_unsigned (); 274 brm_info->self = gcov_read_unsigned (); 275 brm_info->cum = gcov_read_unsigned (); 276 brm_info->code_addr = gcov_read_counter (); 277 brm_info->line = gcov_read_unsigned (); 278 brm_info->discriminator = gcov_read_unsigned (); 279 filename = gcov_read_string (); 280 if (filename) 281 brm_info->filename = gcov_canonical_filename (xstrdup (filename)); 282 else 283 brm_info->filename = 0; 284 } 285 286 /* Read LEN words from an open gcov file and construct data into pmu 287 tool header TOOL_HEADER. */ 288 289 GCOV_LINKAGE void gcov_read_pmu_tool_header (gcov_pmu_tool_header_t *header, 290 gcov_unsigned_t len ATTRIBUTE_UNUSED) 291 { 292 const char *str; 293 str = gcov_read_string (); 294 header->host_cpu = str ? xstrdup (str) : 0; 295 str = gcov_read_string (); 296 header->hostname = str ? xstrdup (str) : 0; 297 str = gcov_read_string (); 298 header->kernel_version = str ? xstrdup (str) : 0; 299 str = gcov_read_string (); 300 header->column_header = str ? xstrdup (str) : 0; 301 str = gcov_read_string (); 302 header->column_description = str ? xstrdup (str) : 0; 303 str = gcov_read_string (); 304 header->full_header = str ? xstrdup (str) : 0; 305 } 306 #endif 307 308 #if !IN_LIBGCOV 309 /* Check if MAGIC is EXPECTED. Use it to determine endianness of the 310 file. Returns +1 for same endian, -1 for other endian and zero for 311 not EXPECTED. */ 312 313 GCOV_LINKAGE int 314 gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected) 315 { 316 if (magic == expected) 317 return 1; 318 magic = (magic >> 16) | (magic << 16); 319 magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff); 320 if (magic == expected) 321 { 322 gcov_var.endian = 1; 323 return -1; 324 } 325 return 0; 326 } 327 #endif 328 329 #if !IN_LIBGCOV 330 static void 331 gcov_allocate (unsigned length) 332 { 333 size_t new_size = gcov_var.alloc; 334 335 if (!new_size) 336 new_size = GCOV_BLOCK_SIZE; 337 new_size += length; 338 new_size *= 2; 339 340 gcov_var.alloc = new_size; 341 gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2); 342 } 343 #endif 344 345 #if !IN_GCOV 346 /* Write out the current block, if needs be. */ 347 348 static void 349 gcov_write_block (unsigned size) 350 { 351 if (_GCOV_fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) 352 gcov_var.error = 1; 353 gcov_var.start += size; 354 gcov_var.offset -= size; 355 } 356 357 #if IN_LIBGCOV 358 /* Return the number of words STRING would need including the length 359 field in the output stream itself. This should be identical to 360 "alloc" calculation in gcov_write_string(). */ 361 362 GCOV_LINKAGE gcov_unsigned_t 363 gcov_string_length (const char *string) 364 { 365 gcov_unsigned_t len = (string) ? strlen (string) : 0; 366 /* + 1 because of the length field. */ 367 gcov_unsigned_t alloc = 1 + ((len + 4) >> 2); 368 369 /* Can not write a bigger than GCOV_BLOCK_SIZE string yet */ 370 gcc_assert (alloc < GCOV_BLOCK_SIZE); 371 return alloc; 372 } 373 #endif 374 375 /* Allocate space to write BYTES bytes to the gcov file. Return a 376 pointer to those bytes, or NULL on failure. */ 377 378 static gcov_unsigned_t * 379 gcov_write_words (unsigned words) 380 { 381 gcov_unsigned_t *result; 382 383 gcc_assert (gcov_var.mode < 0); 384 #if IN_LIBGCOV 385 if (gcov_var.offset + words >= GCOV_BLOCK_SIZE) 386 { 387 gcov_write_block (MIN (gcov_var.offset, GCOV_BLOCK_SIZE)); 388 if (gcov_var.offset) 389 { 390 gcc_assert (gcov_var.offset < GCOV_BLOCK_SIZE); 391 memcpy (gcov_var.buffer, 392 gcov_var.buffer + GCOV_BLOCK_SIZE, 393 gcov_var.offset << 2); 394 } 395 } 396 #else 397 if (gcov_var.offset + words > gcov_var.alloc) 398 gcov_allocate (gcov_var.offset + words); 399 #endif 400 result = &gcov_var.buffer[gcov_var.offset]; 401 gcov_var.offset += words; 402 403 return result; 404 } 405 406 /* Write unsigned VALUE to coverage file. Sets error flag 407 appropriately. */ 408 409 GCOV_LINKAGE void 410 gcov_write_unsigned (gcov_unsigned_t value) 411 { 412 gcov_unsigned_t *buffer = gcov_write_words (1); 413 414 buffer[0] = value; 415 } 416 417 /* Write counter VALUE to coverage file. Sets error flag 418 appropriately. */ 419 420 #if IN_LIBGCOV 421 GCOV_LINKAGE void 422 gcov_write_counter (gcov_type value) 423 { 424 gcov_unsigned_t *buffer = gcov_write_words (2); 425 426 buffer[0] = (gcov_unsigned_t) value; 427 if (sizeof (value) > sizeof (gcov_unsigned_t)) 428 buffer[1] = (gcov_unsigned_t) (value >> 32); 429 else 430 buffer[1] = 0; 431 } 432 #endif /* IN_LIBGCOV */ 433 434 /* Write STRING to coverage file. Sets error flag on file 435 error, overflow flag on overflow */ 436 437 GCOV_LINKAGE void 438 gcov_write_string (const char *string) 439 { 440 unsigned length = 0; 441 unsigned alloc = 0; 442 gcov_unsigned_t *buffer; 443 444 if (string) 445 { 446 length = strlen (string); 447 alloc = (length + 4) >> 2; 448 } 449 450 buffer = gcov_write_words (1 + alloc); 451 452 buffer[0] = alloc; 453 buffer[alloc] = 0; 454 memcpy (&buffer[1], string, length); 455 } 456 457 #if !IN_LIBGCOV 458 /* Write a tag TAG and reserve space for the record length. Return a 459 value to be used for gcov_write_length. */ 460 461 GCOV_LINKAGE gcov_position_t 462 gcov_write_tag (gcov_unsigned_t tag) 463 { 464 gcov_position_t result = gcov_var.start + gcov_var.offset; 465 gcov_unsigned_t *buffer = gcov_write_words (2); 466 467 buffer[0] = tag; 468 buffer[1] = 0; 469 470 return result; 471 } 472 473 /* Write a record length using POSITION, which was returned by 474 gcov_write_tag. The current file position is the end of the 475 record, and is restored before returning. Returns nonzero on 476 overflow. */ 477 478 GCOV_LINKAGE void 479 gcov_write_length (gcov_position_t position) 480 { 481 unsigned offset; 482 gcov_unsigned_t length; 483 gcov_unsigned_t *buffer; 484 485 gcc_assert (gcov_var.mode < 0); 486 gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset); 487 gcc_assert (position >= gcov_var.start); 488 offset = position - gcov_var.start; 489 length = gcov_var.offset - offset - 2; 490 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; 491 buffer[1] = length; 492 if (gcov_var.offset >= GCOV_BLOCK_SIZE) 493 gcov_write_block (gcov_var.offset); 494 } 495 496 #else /* IN_LIBGCOV */ 497 498 /* Write a tag TAG and length LENGTH. */ 499 500 GCOV_LINKAGE void 501 gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) 502 { 503 gcov_unsigned_t *buffer = gcov_write_words (2); 504 505 buffer[0] = tag; 506 buffer[1] = length; 507 } 508 509 /* Write a summary structure to the gcov file. Return nonzero on 510 overflow. */ 511 512 GCOV_LINKAGE void 513 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) 514 { 515 unsigned ix; 516 const struct gcov_ctr_summary *csum; 517 518 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH); 519 gcov_write_unsigned (summary->checksum); 520 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) 521 { 522 gcov_write_unsigned (csum->num); 523 gcov_write_unsigned (csum->runs); 524 gcov_write_counter (csum->sum_all); 525 gcov_write_counter (csum->run_max); 526 gcov_write_counter (csum->sum_max); 527 } 528 } 529 #endif /* IN_LIBGCOV */ 530 531 #endif /*!IN_GCOV */ 532 533 /* Return a pointer to read BYTES bytes from the gcov file. Returns 534 NULL on failure (read past EOF). */ 535 536 static const gcov_unsigned_t * 537 gcov_read_words (unsigned words) 538 { 539 const gcov_unsigned_t *result; 540 unsigned excess = gcov_var.length - gcov_var.offset; 541 542 gcc_assert (gcov_var.mode > 0); 543 gcc_assert (words < GCOV_BLOCK_SIZE); 544 if (excess < words) 545 { 546 gcov_var.start += gcov_var.offset; 547 #if IN_LIBGCOV 548 if (excess) 549 { 550 gcc_assert (excess < GCOV_BLOCK_SIZE); 551 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4); 552 } 553 #else 554 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4); 555 #endif 556 gcov_var.offset = 0; 557 gcov_var.length = excess; 558 #if IN_LIBGCOV 559 excess = (sizeof (gcov_var.buffer) / sizeof (gcov_var.buffer[0])) - gcov_var.length; 560 #else 561 if (gcov_var.length + words > gcov_var.alloc) 562 gcov_allocate (gcov_var.length + words); 563 excess = gcov_var.alloc - gcov_var.length; 564 #endif 565 excess = _GCOV_fread (gcov_var.buffer + gcov_var.length, 566 1, excess << 2, gcov_var.file) >> 2; 567 gcov_var.length += excess; 568 if (gcov_var.length < words) 569 { 570 gcov_var.overread += words - gcov_var.length; 571 gcov_var.length = 0; 572 return 0; 573 } 574 } 575 result = &gcov_var.buffer[gcov_var.offset]; 576 gcov_var.offset += words; 577 return result; 578 } 579 580 /* Read unsigned value from a coverage file. Sets error flag on file 581 error, overflow flag on overflow */ 582 583 GCOV_LINKAGE gcov_unsigned_t 584 gcov_read_unsigned (void) 585 { 586 gcov_unsigned_t value; 587 const gcov_unsigned_t *buffer = gcov_read_words (1); 588 589 if (!buffer) 590 return 0; 591 value = from_file (buffer[0]); 592 return value; 593 } 594 595 /* Read counter value from a coverage file. Sets error flag on file 596 error, overflow flag on overflow */ 597 598 GCOV_LINKAGE gcov_type 599 gcov_read_counter (void) 600 { 601 gcov_type value; 602 const gcov_unsigned_t *buffer = gcov_read_words (2); 603 604 if (!buffer) 605 return 0; 606 value = from_file (buffer[0]); 607 if (sizeof (value) > sizeof (gcov_unsigned_t)) 608 value |= ((gcov_type) from_file (buffer[1])) << 32; 609 else if (buffer[1]) 610 gcov_var.error = -1; 611 612 return value; 613 } 614 615 /* Read string from coverage file. Returns a pointer to a static 616 buffer, or NULL on empty string. You must copy the string before 617 calling another gcov function. */ 618 619 GCOV_LINKAGE const char * 620 gcov_read_string (void) 621 { 622 unsigned length = gcov_read_unsigned (); 623 624 if (!length) 625 return 0; 626 627 return (const char *) gcov_read_words (length); 628 } 629 630 GCOV_LINKAGE void 631 gcov_read_summary (struct gcov_summary *summary) 632 { 633 unsigned ix; 634 struct gcov_ctr_summary *csum; 635 636 summary->checksum = gcov_read_unsigned (); 637 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) 638 { 639 csum->num = gcov_read_unsigned (); 640 csum->runs = gcov_read_unsigned (); 641 csum->sum_all = gcov_read_counter (); 642 csum->run_max = gcov_read_counter (); 643 csum->sum_max = gcov_read_counter (); 644 } 645 } 646 647 #if !IN_LIBGCOV && IN_GCOV != 1 648 /* Read LEN words (unsigned type) and construct MOD_INFO. */ 649 650 GCOV_LINKAGE void 651 gcov_read_module_info (struct gcov_module_info *mod_info, 652 gcov_unsigned_t len) 653 { 654 gcov_unsigned_t src_filename_len, filename_len, i, j, num_strings; 655 mod_info->ident = gcov_read_unsigned (); 656 mod_info->is_primary = gcov_read_unsigned (); 657 mod_info->is_exported = gcov_read_unsigned (); 658 mod_info->lang = gcov_read_unsigned (); 659 mod_info->num_quote_paths = gcov_read_unsigned (); 660 mod_info->num_bracket_paths = gcov_read_unsigned (); 661 mod_info->num_cpp_defines = gcov_read_unsigned (); 662 mod_info->num_cpp_includes = gcov_read_unsigned (); 663 mod_info->num_cl_args = gcov_read_unsigned (); 664 len -= 9; 665 666 filename_len = gcov_read_unsigned (); 667 mod_info->da_filename = (char *) xmalloc (filename_len * 668 sizeof (gcov_unsigned_t)); 669 for (i = 0; i < filename_len; i++) 670 ((gcov_unsigned_t *) mod_info->da_filename)[i] = gcov_read_unsigned (); 671 len -= (filename_len + 1); 672 673 src_filename_len = gcov_read_unsigned (); 674 mod_info->source_filename = (char *) xmalloc (src_filename_len * 675 sizeof (gcov_unsigned_t)); 676 for (i = 0; i < src_filename_len; i++) 677 ((gcov_unsigned_t *) mod_info->source_filename)[i] = gcov_read_unsigned (); 678 len -= (src_filename_len + 1); 679 680 num_strings = mod_info->num_quote_paths + mod_info->num_bracket_paths + 681 mod_info->num_cpp_defines + mod_info->num_cpp_includes + 682 mod_info->num_cl_args; 683 for (j = 0; j < num_strings; j++) 684 { 685 gcov_unsigned_t string_len = gcov_read_unsigned (); 686 mod_info->string_array[j] = 687 (char *) xmalloc (string_len * sizeof (gcov_unsigned_t)); 688 for (i = 0; i < string_len; i++) 689 ((gcov_unsigned_t *) mod_info->string_array[j])[i] = 690 gcov_read_unsigned (); 691 len -= (string_len + 1); 692 } 693 gcc_assert (!len); 694 } 695 #endif 696 697 #if !IN_LIBGCOV 698 /* Reset to a known position. BASE should have been obtained from 699 gcov_position, LENGTH should be a record length. */ 700 701 GCOV_LINKAGE void 702 gcov_sync (gcov_position_t base, gcov_unsigned_t length) 703 { 704 #ifdef __GCOV_KERNEL__ 705 /* should not reach this point */ 706 gcc_assert (0); 707 #else /* __GCOV_KERNEL__ */ 708 gcc_assert (gcov_var.mode > 0); 709 base += length; 710 if (base - gcov_var.start <= gcov_var.length) 711 gcov_var.offset = base - gcov_var.start; 712 else 713 { 714 gcov_var.offset = gcov_var.length = 0; 715 _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET); 716 gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2; 717 } 718 #endif /* __GCOV_KERNEL__ */ 719 } 720 #endif 721 722 #if IN_LIBGCOV 723 /* Move to a given position in a gcov file. */ 724 725 GCOV_LINKAGE void 726 gcov_seek (gcov_position_t base) 727 { 728 gcc_assert (gcov_var.mode < 0); 729 if (gcov_var.offset) 730 gcov_write_block (gcov_var.offset); 731 _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET); 732 gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2; 733 } 734 735 /* Truncate the gcov file at the current position. */ 736 737 GCOV_LINKAGE void 738 gcov_truncate (void) 739 { 740 #ifdef __GCOV_KERNEL__ 741 /* should not reach this point */ 742 gcc_assert (0); 743 #else /* __GCOV_KERNEL__ */ 744 long offs; 745 int filenum; 746 gcc_assert (gcov_var.mode < 0); 747 if (gcov_var.offset) 748 gcov_write_block (gcov_var.offset); 749 offs = ftell (gcov_var.file); 750 filenum = fileno (gcov_var.file); 751 if (offs == -1 || filenum == -1 || ftruncate (filenum, offs)) 752 gcov_var.error = 1; 753 #endif /* __GCOV_KERNEL__ */ 754 } 755 #endif 756 757 #ifndef __GCOV_KERNEL__ 758 /* Convert an unsigned NUMBER to a percentage after dividing by 759 100. */ 760 761 GCOV_LINKAGE float 762 convert_unsigned_to_pct (const unsigned number) 763 { 764 return (float)number / 100.0f; 765 } 766 #endif 767 768 #if !IN_LIBGCOV && IN_GCOV != 1 769 /* Print load latency information given by LL_INFO in a human readable 770 format into an open output file pointed by FP. NEWLINE specifies 771 whether or not to print a trailing newline. */ 772 773 GCOV_LINKAGE void 774 print_load_latency_line (FILE *fp, const gcov_pmu_ll_info_t *ll_info, 775 const enum print_newline newline) 776 { 777 if (!ll_info) 778 return; 779 fprintf (fp, " %u %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% %.2f%% " 780 "%.2f%% %.2f%% " HOST_WIDEST_INT_PRINT_HEX " %s %d %d", 781 ll_info->counts, 782 convert_unsigned_to_pct (ll_info->self), 783 convert_unsigned_to_pct (ll_info->cum), 784 convert_unsigned_to_pct (ll_info->lt_10), 785 convert_unsigned_to_pct (ll_info->lt_32), 786 convert_unsigned_to_pct (ll_info->lt_64), 787 convert_unsigned_to_pct (ll_info->lt_256), 788 convert_unsigned_to_pct (ll_info->lt_1024), 789 convert_unsigned_to_pct (ll_info->gt_1024), 790 convert_unsigned_to_pct (ll_info->wself), 791 ll_info->code_addr, 792 ll_info->filename, 793 ll_info->line, 794 ll_info->discriminator); 795 if (newline == add_newline) 796 fprintf (fp, "\n"); 797 } 798 799 /* Print BRM_INFO into the file pointed by FP. NEWLINE specifies 800 whether or not to print a trailing newline. */ 801 802 GCOV_LINKAGE void 803 print_branch_mispredict_line (FILE *fp, const gcov_pmu_brm_info_t *brm_info, 804 const enum print_newline newline) 805 { 806 if (!brm_info) 807 return; 808 fprintf (fp, " %u %.2f%% %.2f%% " HOST_WIDEST_INT_PRINT_HEX " %s %d %d", 809 brm_info->counts, 810 convert_unsigned_to_pct (brm_info->self), 811 convert_unsigned_to_pct (brm_info->cum), 812 brm_info->code_addr, 813 brm_info->filename, 814 brm_info->line, 815 brm_info->discriminator); 816 if (newline == add_newline) 817 fprintf (fp, "\n"); 818 } 819 820 /* Print TOOL_HEADER into the file pointed by FP. NEWLINE specifies 821 whether or not to print a trailing newline. */ 822 823 GCOV_LINKAGE void 824 print_pmu_tool_header (FILE *fp, gcov_pmu_tool_header_t *tool_header, 825 const enum print_newline newline) 826 { 827 if (!tool_header) 828 return; 829 fprintf (fp, "\nhost_cpu: %s\n", tool_header->host_cpu); 830 fprintf (fp, "hostname: %s\n", tool_header->hostname); 831 fprintf (fp, "kernel_version: %s\n", tool_header->kernel_version); 832 fprintf (fp, "column_header: %s\n", tool_header->column_header); 833 fprintf (fp, "column_description: %s\n", tool_header->column_description); 834 fprintf (fp, "full_header: %s\n", tool_header->full_header); 835 if (newline == add_newline) 836 fprintf (fp, "\n"); 837 } 838 #endif 839 840 #if IN_GCOV > 0 841 /* Return the modification time of the current gcov file. */ 842 843 GCOV_LINKAGE time_t 844 gcov_time (void) 845 { 846 struct stat status; 847 848 if (fstat (fileno (gcov_var.file), &status)) 849 return 0; 850 else 851 return status.st_mtime; 852 } 853 #endif /* IN_GCOV */ 854 855 #ifdef __GCOV_KERNEL__ 856 857 /* File fclose operation in kernel mode. */ 858 859 int 860 kernel_file_fclose (gcov_kernel_vfile *fp) 861 { 862 return 0; 863 } 864 865 /* File ftell operation in kernel mode. It currently should not 866 be called. */ 867 868 long 869 kernel_file_ftell (gcov_kernel_vfile *fp) 870 { 871 gcc_assert (0); /* should not reach here */ 872 return 0; 873 } 874 875 /* File fseek operation in kernel mode. It should only be called 876 with OFFSET==0 and WHENCE==0 to a freshly opened file. */ 877 878 int 879 kernel_file_fseek (gcov_kernel_vfile *fp, long offset, int whence) 880 { 881 gcc_assert (offset == 0 && whence == 0 && fp->count == 0); 882 return 0; 883 } 884 885 /* File ftruncate operation in kernel mode. It currently should not 886 be called. */ 887 888 int 889 kernel_file_ftruncate (gcov_kernel_vfile *fp, off_t value) 890 { 891 gcc_assert (0); /* should not reach here */ 892 return 0; 893 } 894 895 /* File fread operation in kernel mode. It currently should not 896 be called. */ 897 898 int 899 kernel_file_fread (void *ptr, size_t size, size_t nitems, 900 gcov_kernel_vfile *fp) 901 { 902 gcc_assert (0); /* should not reach here */ 903 return 0; 904 } 905 906 /* File fwrite operation in kernel mode. It outputs the data 907 to a buffer in the virual file. */ 908 909 int 910 kernel_file_fwrite (const void *ptr, size_t size, 911 size_t nitems, gcov_kernel_vfile *fp) 912 { 913 char *vbuf; 914 unsigned vsize, vpos; 915 unsigned len; 916 917 if (!fp) return 0; 918 919 vbuf = fp->buf; 920 vsize = fp->size; 921 vpos = fp->count; 922 923 if (vsize <= vpos) 924 { 925 printk (KERN_ERR 926 "GCOV_KERNEL: something wrong: vbuf=%p vsize=%u vpos=%u\n", 927 vbuf, vsize, vpos); 928 return 0; 929 } 930 len = vsize - vpos; 931 len /= size; 932 933 if (len > nitems) 934 len = nitems; 935 936 memcpy (vbuf+vpos, ptr, size*len); 937 fp->count += len*size; 938 939 if (len != nitems) 940 printk (KERN_ERR 941 "GCOV_KERNEL: something wrong: size=%lu nitems=%lu ret=%d\n", 942 size, nitems, len); 943 return len; 944 } 945 946 /* File fileno operation in kernel mode. It currently should not 947 be called. */ 948 949 int 950 kernel_file_fileno (gcov_kernel_vfile *fp) 951 { 952 gcc_assert (0); /* should not reach here */ 953 return 0; 954 } 955 #else /* __GCOV_KERNEL__ */ 956 957 #if IN_GCOV != 1 958 /* Delete pmu tool header TOOL_HEADER. */ 959 960 GCOV_LINKAGE void 961 destroy_pmu_tool_header (gcov_pmu_tool_header_t *tool_header) 962 { 963 if (!tool_header) 964 return; 965 if (tool_header->host_cpu) 966 free (tool_header->host_cpu); 967 if (tool_header->hostname) 968 free (tool_header->hostname); 969 if (tool_header->kernel_version) 970 free (tool_header->kernel_version); 971 if (tool_header->column_header) 972 free (tool_header->column_header); 973 if (tool_header->column_description) 974 free (tool_header->column_description); 975 if (tool_header->full_header) 976 free (tool_header->full_header); 977 } 978 #endif 979 980 #endif /* GCOV_KERNEL */ 981