1 /*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ 2 |* 3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 |* See https://llvm.org/LICENSE.txt for license information. 5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 |* 7 |*===----------------------------------------------------------------------===*| 8 |* 9 |* This file implements the call back routines for the gcov profiling 10 |* instrumentation pass. Link against this library when running code through 11 |* the -insert-gcov-profiling LLVM pass. 12 |* 13 |* We emit files in a corrupt version of GCOV's "gcda" file format. These files 14 |* are only close enough that LCOV will happily parse them. Anything that lcov 15 |* ignores is missing. 16 |* 17 |* TODO: gcov is multi-process safe by having each exit open the existing file 18 |* and append to it. We'd like to achieve that and be thread-safe too. 19 |* 20 \*===----------------------------------------------------------------------===*/ 21 22 #if !defined(__Fuchsia__) 23 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #if defined(_WIN32) 31 #define WIN32_LEAN_AND_MEAN 32 #include <windows.h> 33 #include "WindowsMMap.h" 34 #else 35 #include <sys/mman.h> 36 #include <sys/file.h> 37 #endif 38 39 #if defined(__FreeBSD__) && defined(__i386__) 40 #define I386_FREEBSD 1 41 #else 42 #define I386_FREEBSD 0 43 #endif 44 45 #if !defined(_MSC_VER) && !I386_FREEBSD 46 #include <stdint.h> 47 #endif 48 49 #if defined(_MSC_VER) 50 typedef unsigned char uint8_t; 51 typedef unsigned int uint32_t; 52 typedef unsigned long long uint64_t; 53 #elif I386_FREEBSD 54 /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to 55 * FreeBSD 10, r232261) when compiled in 32-bit mode. 56 */ 57 typedef unsigned char uint8_t; 58 typedef unsigned int uint32_t; 59 typedef unsigned long long uint64_t; 60 #endif 61 62 #include "InstrProfiling.h" 63 #include "InstrProfilingUtil.h" 64 65 /* #define DEBUG_GCDAPROFILING */ 66 67 /* 68 * --- GCOV file format I/O primitives --- 69 */ 70 71 /* 72 * The current file name we're outputting. Used primarily for error logging. 73 */ 74 static char *filename = NULL; 75 76 /* 77 * The current file we're outputting. 78 */ 79 static FILE *output_file = NULL; 80 81 /* 82 * Buffer that we write things into. 83 */ 84 #define WRITE_BUFFER_SIZE (128 * 1024) 85 static unsigned char *write_buffer = NULL; 86 static uint64_t cur_buffer_size = 0; 87 static uint64_t cur_pos = 0; 88 static uint64_t file_size = 0; 89 static int new_file = 0; 90 #if defined(_WIN32) 91 static HANDLE mmap_handle = NULL; 92 #endif 93 static int fd = -1; 94 95 typedef void (*fn_ptr)(); 96 97 typedef void* dynamic_object_id; 98 // The address of this variable identifies a given dynamic object. 99 static dynamic_object_id current_id; 100 #define CURRENT_ID (¤t_id) 101 102 struct fn_node { 103 dynamic_object_id id; 104 fn_ptr fn; 105 struct fn_node* next; 106 }; 107 108 struct fn_list { 109 struct fn_node *head, *tail; 110 }; 111 112 /* 113 * A list of functions to write out the data, shared between all dynamic objects. 114 */ 115 struct fn_list writeout_fn_list; 116 117 /* 118 * A list of flush functions that our __gcov_flush() function should call, shared between all dynamic objects. 119 */ 120 struct fn_list flush_fn_list; 121 122 static void fn_list_insert(struct fn_list* list, fn_ptr fn) { 123 struct fn_node* new_node = malloc(sizeof(struct fn_node)); 124 new_node->fn = fn; 125 new_node->next = NULL; 126 new_node->id = CURRENT_ID; 127 128 if (!list->head) { 129 list->head = list->tail = new_node; 130 } else { 131 list->tail->next = new_node; 132 list->tail = new_node; 133 } 134 } 135 136 static void fn_list_remove(struct fn_list* list) { 137 struct fn_node* curr = list->head; 138 struct fn_node* prev = NULL; 139 struct fn_node* next = NULL; 140 141 while (curr) { 142 next = curr->next; 143 144 if (curr->id == CURRENT_ID) { 145 if (curr == list->head) { 146 list->head = next; 147 } 148 149 if (curr == list->tail) { 150 list->tail = prev; 151 } 152 153 if (prev) { 154 prev->next = next; 155 } 156 157 free(curr); 158 } else { 159 prev = curr; 160 } 161 162 curr = next; 163 } 164 } 165 166 static void resize_write_buffer(uint64_t size) { 167 if (!new_file) return; 168 size += cur_pos; 169 if (size <= cur_buffer_size) return; 170 size = (size - 1) / WRITE_BUFFER_SIZE + 1; 171 size *= WRITE_BUFFER_SIZE; 172 write_buffer = realloc(write_buffer, size); 173 cur_buffer_size = size; 174 } 175 176 static void write_bytes(const char *s, size_t len) { 177 resize_write_buffer(len); 178 memcpy(&write_buffer[cur_pos], s, len); 179 cur_pos += len; 180 } 181 182 static void write_32bit_value(uint32_t i) { 183 write_bytes((char*)&i, 4); 184 } 185 186 static void write_64bit_value(uint64_t i) { 187 // GCOV uses a lo-/hi-word format even on big-endian systems. 188 // See also GCOVBuffer::readInt64 in LLVM. 189 uint32_t lo = (uint32_t) i; 190 uint32_t hi = (uint32_t) (i >> 32); 191 write_32bit_value(lo); 192 write_32bit_value(hi); 193 } 194 195 static uint32_t length_of_string(const char *s) { 196 return (strlen(s) / 4) + 1; 197 } 198 199 static void write_string(const char *s) { 200 uint32_t len = length_of_string(s); 201 write_32bit_value(len); 202 write_bytes(s, strlen(s)); 203 write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); 204 } 205 206 static uint32_t read_32bit_value() { 207 uint32_t val; 208 209 if (new_file) 210 return (uint32_t)-1; 211 212 val = *(uint32_t*)&write_buffer[cur_pos]; 213 cur_pos += 4; 214 return val; 215 } 216 217 static uint32_t read_le_32bit_value() { 218 uint32_t val = 0; 219 int i; 220 221 if (new_file) 222 return (uint32_t)-1; 223 224 for (i = 0; i < 4; i++) 225 val |= write_buffer[cur_pos++] << (8*i); 226 return val; 227 } 228 229 static uint64_t read_64bit_value() { 230 // GCOV uses a lo-/hi-word format even on big-endian systems. 231 // See also GCOVBuffer::readInt64 in LLVM. 232 uint32_t lo = read_32bit_value(); 233 uint32_t hi = read_32bit_value(); 234 return ((uint64_t)hi << 32) | ((uint64_t)lo); 235 } 236 237 static char *mangle_filename(const char *orig_filename) { 238 char *new_filename; 239 size_t prefix_len; 240 int prefix_strip; 241 const char *prefix = lprofGetPathPrefix(&prefix_strip, &prefix_len); 242 243 if (prefix == NULL) 244 return strdup(orig_filename); 245 246 new_filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1); 247 lprofApplyPathPrefix(new_filename, orig_filename, prefix, prefix_len, 248 prefix_strip); 249 250 return new_filename; 251 } 252 253 static int map_file() { 254 fseek(output_file, 0L, SEEK_END); 255 file_size = ftell(output_file); 256 257 /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an 258 * error message because it should "just work" for the user. */ 259 if (file_size == 0) 260 return -1; 261 262 #if defined(_WIN32) 263 HANDLE mmap_fd; 264 if (fd == -1) 265 mmap_fd = INVALID_HANDLE_VALUE; 266 else 267 mmap_fd = (HANDLE)_get_osfhandle(fd); 268 269 mmap_handle = CreateFileMapping(mmap_fd, NULL, PAGE_READWRITE, DWORD_HI(file_size), DWORD_LO(file_size), NULL); 270 if (mmap_handle == NULL) { 271 fprintf(stderr, "profiling: %s: cannot create file mapping: %lu\n", 272 filename, GetLastError()); 273 return -1; 274 } 275 276 write_buffer = MapViewOfFile(mmap_handle, FILE_MAP_WRITE, 0, 0, file_size); 277 if (write_buffer == NULL) { 278 fprintf(stderr, "profiling: %s: cannot map: %lu\n", filename, 279 GetLastError()); 280 CloseHandle(mmap_handle); 281 return -1; 282 } 283 #else 284 write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, 285 MAP_FILE | MAP_SHARED, fd, 0); 286 if (write_buffer == (void *)-1) { 287 int errnum = errno; 288 fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, 289 strerror(errnum)); 290 return -1; 291 } 292 #endif 293 294 return 0; 295 } 296 297 static void unmap_file() { 298 #if defined(_WIN32) 299 if (!FlushViewOfFile(write_buffer, file_size)) { 300 fprintf(stderr, "profiling: %s: cannot flush mapped view: %lu\n", filename, 301 GetLastError()); 302 } 303 304 if (!UnmapViewOfFile(write_buffer)) { 305 fprintf(stderr, "profiling: %s: cannot unmap mapped view: %lu\n", filename, 306 GetLastError()); 307 } 308 309 if (!CloseHandle(mmap_handle)) { 310 fprintf(stderr, "profiling: %s: cannot close file mapping handle: %lu\n", 311 filename, GetLastError()); 312 } 313 314 mmap_handle = NULL; 315 #else 316 if (msync(write_buffer, file_size, MS_SYNC) == -1) { 317 int errnum = errno; 318 fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, 319 strerror(errnum)); 320 } 321 322 /* We explicitly ignore errors from unmapping because at this point the data 323 * is written and we don't care. 324 */ 325 (void)munmap(write_buffer, file_size); 326 #endif 327 328 write_buffer = NULL; 329 file_size = 0; 330 } 331 332 /* 333 * --- LLVM line counter API --- 334 */ 335 336 /* A file in this case is a translation unit. Each .o file built with line 337 * profiling enabled will emit to a different file. Only one file may be 338 * started at a time. 339 */ 340 COMPILER_RT_VISIBILITY 341 void llvm_gcda_start_file(const char *orig_filename, const char version[4], 342 uint32_t checksum) { 343 const char *mode = "r+b"; 344 filename = mangle_filename(orig_filename); 345 346 /* Try just opening the file. */ 347 new_file = 0; 348 fd = open(filename, O_RDWR | O_BINARY); 349 350 if (fd == -1) { 351 /* Try creating the file. */ 352 fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644); 353 if (fd != -1) { 354 new_file = 1; 355 mode = "w+b"; 356 } else { 357 /* Try creating the directories first then opening the file. */ 358 __llvm_profile_recursive_mkdir(filename); 359 fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644); 360 if (fd != -1) { 361 new_file = 1; 362 mode = "w+b"; 363 } else { 364 /* Another process may have created the file just now. 365 * Try opening it without O_CREAT and O_EXCL. */ 366 fd = open(filename, O_RDWR | O_BINARY); 367 if (fd == -1) { 368 /* Bah! It's hopeless. */ 369 int errnum = errno; 370 fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, 371 strerror(errnum)); 372 return; 373 } 374 } 375 } 376 } 377 378 /* Try to flock the file to serialize concurrent processes writing out to the 379 * same GCDA. This can fail if the filesystem doesn't support it, but in that 380 * case we'll just carry on with the old racy behaviour and hope for the best. 381 */ 382 lprofLockFd(fd); 383 output_file = fdopen(fd, mode); 384 385 /* Initialize the write buffer. */ 386 write_buffer = NULL; 387 cur_buffer_size = 0; 388 cur_pos = 0; 389 390 if (new_file) { 391 resize_write_buffer(WRITE_BUFFER_SIZE); 392 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 393 } else { 394 if (map_file() == -1) { 395 /* mmap failed, try to recover by clobbering */ 396 new_file = 1; 397 write_buffer = NULL; 398 cur_buffer_size = 0; 399 resize_write_buffer(WRITE_BUFFER_SIZE); 400 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 401 } 402 } 403 404 /* gcda file, version, stamp checksum. */ 405 write_bytes("adcg", 4); 406 write_bytes(version, 4); 407 write_32bit_value(checksum); 408 409 #ifdef DEBUG_GCDAPROFILING 410 fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 411 #endif 412 } 413 414 /* Given an array of pointers to counters (counters), increment the n-th one, 415 * where we're also given a pointer to n (predecessor). 416 */ 417 COMPILER_RT_VISIBILITY 418 void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 419 uint64_t **counters) { 420 uint64_t *counter; 421 uint32_t pred; 422 423 pred = *predecessor; 424 if (pred == 0xffffffff) 425 return; 426 counter = counters[pred]; 427 428 /* Don't crash if the pred# is out of sync. This can happen due to threads, 429 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 430 if (counter) 431 ++*counter; 432 #ifdef DEBUG_GCDAPROFILING 433 else 434 fprintf(stderr, 435 "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 436 *counter, *predecessor); 437 #endif 438 } 439 440 COMPILER_RT_VISIBILITY 441 void llvm_gcda_emit_function(uint32_t ident, const char *function_name, 442 uint32_t func_checksum, uint8_t use_extra_checksum, 443 uint32_t cfg_checksum) { 444 uint32_t len = 2; 445 446 if (use_extra_checksum) 447 len++; 448 #ifdef DEBUG_GCDAPROFILING 449 fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 450 function_name ? function_name : "NULL"); 451 #endif 452 if (!output_file) return; 453 454 /* function tag */ 455 write_bytes("\0\0\0\1", 4); 456 if (function_name) 457 len += 1 + length_of_string(function_name); 458 write_32bit_value(len); 459 write_32bit_value(ident); 460 write_32bit_value(func_checksum); 461 if (use_extra_checksum) 462 write_32bit_value(cfg_checksum); 463 if (function_name) 464 write_string(function_name); 465 } 466 467 COMPILER_RT_VISIBILITY 468 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 469 uint32_t i; 470 uint64_t *old_ctrs = NULL; 471 uint32_t val = 0; 472 uint64_t save_cur_pos = cur_pos; 473 474 if (!output_file) return; 475 476 val = read_le_32bit_value(); 477 478 if (val != (uint32_t)-1) { 479 /* There are counters present in the file. Merge them. */ 480 if (val != 0x01a10000) { 481 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 482 "corrupt arc tag (0x%08x)\n", 483 filename, val); 484 return; 485 } 486 487 val = read_32bit_value(); 488 if (val == (uint32_t)-1 || val / 2 != num_counters) { 489 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 490 "mismatched number of counters (%d)\n", 491 filename, val); 492 return; 493 } 494 495 old_ctrs = malloc(sizeof(uint64_t) * num_counters); 496 for (i = 0; i < num_counters; ++i) 497 old_ctrs[i] = read_64bit_value(); 498 } 499 500 cur_pos = save_cur_pos; 501 502 /* Counter #1 (arcs) tag */ 503 write_bytes("\0\0\xa1\1", 4); 504 write_32bit_value(num_counters * 2); 505 for (i = 0; i < num_counters; ++i) { 506 counters[i] += (old_ctrs ? old_ctrs[i] : 0); 507 write_64bit_value(counters[i]); 508 } 509 510 free(old_ctrs); 511 512 #ifdef DEBUG_GCDAPROFILING 513 fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 514 for (i = 0; i < num_counters; ++i) 515 fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 516 #endif 517 } 518 519 COMPILER_RT_VISIBILITY 520 void llvm_gcda_summary_info() { 521 const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ 522 uint32_t i; 523 uint32_t runs = 1; 524 static uint32_t run_counted = 0; // We only want to increase the run count once. 525 uint32_t val = 0; 526 uint64_t save_cur_pos = cur_pos; 527 528 if (!output_file) return; 529 530 val = read_le_32bit_value(); 531 532 if (val != (uint32_t)-1) { 533 /* There are counters present in the file. Merge them. */ 534 if (val != 0xa1000000) { 535 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 536 "corrupt object tag (0x%08x)\n", 537 filename, val); 538 return; 539 } 540 541 val = read_32bit_value(); /* length */ 542 if (val != obj_summary_len) { 543 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 544 "mismatched object length (%d)\n", 545 filename, val); 546 return; 547 } 548 549 read_32bit_value(); /* checksum, unused */ 550 read_32bit_value(); /* num, unused */ 551 uint32_t prev_runs = read_32bit_value(); 552 /* Add previous run count to new counter, if not already counted before. */ 553 runs = run_counted ? prev_runs : prev_runs + 1; 554 } 555 556 cur_pos = save_cur_pos; 557 558 /* Object summary tag */ 559 write_bytes("\0\0\0\xa1", 4); 560 write_32bit_value(obj_summary_len); 561 write_32bit_value(0); /* checksum, unused */ 562 write_32bit_value(0); /* num, unused */ 563 write_32bit_value(runs); 564 for (i = 3; i < obj_summary_len; ++i) 565 write_32bit_value(0); 566 567 /* Program summary tag */ 568 write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ 569 write_32bit_value(0); /* 0 length */ 570 571 run_counted = 1; 572 573 #ifdef DEBUG_GCDAPROFILING 574 fprintf(stderr, "llvmgcda: %u runs\n", runs); 575 #endif 576 } 577 578 COMPILER_RT_VISIBILITY 579 void llvm_gcda_end_file() { 580 /* Write out EOF record. */ 581 if (output_file) { 582 write_bytes("\0\0\0\0\0\0\0\0", 8); 583 584 if (new_file) { 585 fwrite(write_buffer, cur_pos, 1, output_file); 586 free(write_buffer); 587 } else { 588 unmap_file(); 589 } 590 591 fflush(output_file); 592 lprofUnlockFd(fd); 593 fclose(output_file); 594 output_file = NULL; 595 write_buffer = NULL; 596 } 597 free(filename); 598 599 #ifdef DEBUG_GCDAPROFILING 600 fprintf(stderr, "llvmgcda: -----\n"); 601 #endif 602 } 603 604 COMPILER_RT_VISIBILITY 605 void llvm_register_writeout_function(fn_ptr fn) { 606 fn_list_insert(&writeout_fn_list, fn); 607 } 608 609 COMPILER_RT_VISIBILITY 610 void llvm_writeout_files(void) { 611 struct fn_node *curr = writeout_fn_list.head; 612 613 while (curr) { 614 if (curr->id == CURRENT_ID) { 615 curr->fn(); 616 } 617 curr = curr->next; 618 } 619 } 620 621 COMPILER_RT_VISIBILITY 622 void llvm_delete_writeout_function_list(void) { 623 fn_list_remove(&writeout_fn_list); 624 } 625 626 COMPILER_RT_VISIBILITY 627 void llvm_register_flush_function(fn_ptr fn) { 628 fn_list_insert(&flush_fn_list, fn); 629 } 630 631 void __gcov_flush() { 632 struct fn_node* curr = flush_fn_list.head; 633 634 while (curr) { 635 curr->fn(); 636 curr = curr->next; 637 } 638 } 639 640 COMPILER_RT_VISIBILITY 641 void llvm_delete_flush_function_list(void) { 642 fn_list_remove(&flush_fn_list); 643 } 644 645 COMPILER_RT_VISIBILITY 646 void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn) { 647 static int atexit_ran = 0; 648 649 if (wfn) 650 llvm_register_writeout_function(wfn); 651 652 if (ffn) 653 llvm_register_flush_function(ffn); 654 655 if (atexit_ran == 0) { 656 atexit_ran = 1; 657 658 /* Make sure we write out the data and delete the data structures. */ 659 atexit(llvm_delete_flush_function_list); 660 atexit(llvm_delete_writeout_function_list); 661 atexit(llvm_writeout_files); 662 } 663 } 664 665 #endif 666