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@cygnus.com>. 5 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>. 6 7This file is part of GCC. 8 9GCC is free software; you can redistribute it and/or modify it under 10the terms of the GNU General Public License as published by the Free 11Software Foundation; either version 3, or (at your option) any later 12version. 13 14GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15WARRANTY; without even the implied warranty of MERCHANTABILITY or 16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17for more details. 18 19Under Section 7 of GPL version 3, you are granted additional 20permissions described in the GCC Runtime Library Exception, version 213.1, as published by the Free Software Foundation. 22 23You should have received a copy of the GNU General Public License and 24a copy of the GCC Runtime Library Exception along with this program; 25see 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 38static void gcov_write_block (unsigned); 39static gcov_unsigned_t *gcov_write_words (unsigned); 40#endif 41static const gcov_unsigned_t *gcov_read_words (unsigned); 42#if !IN_LIBGCOV 43static void gcov_allocate (unsigned); 44#endif 45 46#ifdef __GCOV_KERNEL__ 47struct gcov_var gcov_var ATTRIBUTE_HIDDEN; 48#endif 49 50static 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__ 73GCOV_LINKAGE int 74#if IN_LIBGCOV 75gcov_open (const char *name) 76#else 77gcov_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 169extern _GCOV_FILE *gcov_current_file; 170 171GCOV_LINKAGE int 172gcov_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 188GCOV_LINKAGE int 189gcov_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 215GCOV_LINKAGE char * 216gcov_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 241GCOV_LINKAGE void 242gcov_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 268GCOV_LINKAGE void 269gcov_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 289GCOV_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 313GCOV_LINKAGE int 314gcov_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 330static void 331gcov_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 348static void 349gcov_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 362GCOV_LINKAGE gcov_unsigned_t 363gcov_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 378static gcov_unsigned_t * 379gcov_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 409GCOV_LINKAGE void 410gcov_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 421GCOV_LINKAGE void 422gcov_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 437GCOV_LINKAGE void 438gcov_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 461GCOV_LINKAGE gcov_position_t 462gcov_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 478GCOV_LINKAGE void 479gcov_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 500GCOV_LINKAGE void 501gcov_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 512GCOV_LINKAGE void 513gcov_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 536static const gcov_unsigned_t * 537gcov_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 583GCOV_LINKAGE gcov_unsigned_t 584gcov_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 598GCOV_LINKAGE gcov_type 599gcov_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 619GCOV_LINKAGE const char * 620gcov_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 630GCOV_LINKAGE void 631gcov_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 650GCOV_LINKAGE void 651gcov_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 701GCOV_LINKAGE void 702gcov_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 725GCOV_LINKAGE void 726gcov_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 737GCOV_LINKAGE void 738gcov_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 761GCOV_LINKAGE float 762convert_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 773GCOV_LINKAGE void 774print_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 802GCOV_LINKAGE void 803print_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 823GCOV_LINKAGE void 824print_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 843GCOV_LINKAGE time_t 844gcov_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 859int 860kernel_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 868long 869kernel_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 878int 879kernel_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 888int 889kernel_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 898int 899kernel_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 909int 910kernel_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 949int 950kernel_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 960GCOV_LINKAGE void 961destroy_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