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 opening the file, creating it if necessary. */ 352 new_file = 1; 353 mode = "w+b"; 354 fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644); 355 if (fd == -1) { 356 /* Try creating the directories first then opening the file. */ 357 __llvm_profile_recursive_mkdir(filename); 358 fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644); 359 if (fd == -1) { 360 /* Bah! It's hopeless. */ 361 int errnum = errno; 362 fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, 363 strerror(errnum)); 364 return; 365 } 366 } 367 } 368 369 /* Try to flock the file to serialize concurrent processes writing out to the 370 * same GCDA. This can fail if the filesystem doesn't support it, but in that 371 * case we'll just carry on with the old racy behaviour and hope for the best. 372 */ 373 lprofLockFd(fd); 374 output_file = fdopen(fd, mode); 375 376 /* Initialize the write buffer. */ 377 write_buffer = NULL; 378 cur_buffer_size = 0; 379 cur_pos = 0; 380 381 if (new_file) { 382 resize_write_buffer(WRITE_BUFFER_SIZE); 383 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 384 } else { 385 if (map_file() == -1) { 386 /* mmap failed, try to recover by clobbering */ 387 new_file = 1; 388 write_buffer = NULL; 389 cur_buffer_size = 0; 390 resize_write_buffer(WRITE_BUFFER_SIZE); 391 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 392 } 393 } 394 395 /* gcda file, version, stamp checksum. */ 396 write_bytes("adcg", 4); 397 write_bytes(version, 4); 398 write_32bit_value(checksum); 399 400 #ifdef DEBUG_GCDAPROFILING 401 fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 402 #endif 403 } 404 405 /* Given an array of pointers to counters (counters), increment the n-th one, 406 * where we're also given a pointer to n (predecessor). 407 */ 408 COMPILER_RT_VISIBILITY 409 void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 410 uint64_t **counters) { 411 uint64_t *counter; 412 uint32_t pred; 413 414 pred = *predecessor; 415 if (pred == 0xffffffff) 416 return; 417 counter = counters[pred]; 418 419 /* Don't crash if the pred# is out of sync. This can happen due to threads, 420 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 421 if (counter) 422 ++*counter; 423 #ifdef DEBUG_GCDAPROFILING 424 else 425 fprintf(stderr, 426 "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 427 *counter, *predecessor); 428 #endif 429 } 430 431 COMPILER_RT_VISIBILITY 432 void llvm_gcda_emit_function(uint32_t ident, const char *function_name, 433 uint32_t func_checksum, uint8_t use_extra_checksum, 434 uint32_t cfg_checksum) { 435 uint32_t len = 2; 436 437 if (use_extra_checksum) 438 len++; 439 #ifdef DEBUG_GCDAPROFILING 440 fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 441 function_name ? function_name : "NULL"); 442 #endif 443 if (!output_file) return; 444 445 /* function tag */ 446 write_bytes("\0\0\0\1", 4); 447 if (function_name) 448 len += 1 + length_of_string(function_name); 449 write_32bit_value(len); 450 write_32bit_value(ident); 451 write_32bit_value(func_checksum); 452 if (use_extra_checksum) 453 write_32bit_value(cfg_checksum); 454 if (function_name) 455 write_string(function_name); 456 } 457 458 COMPILER_RT_VISIBILITY 459 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 460 uint32_t i; 461 uint64_t *old_ctrs = NULL; 462 uint32_t val = 0; 463 uint64_t save_cur_pos = cur_pos; 464 465 if (!output_file) return; 466 467 val = read_le_32bit_value(); 468 469 if (val != (uint32_t)-1) { 470 /* There are counters present in the file. Merge them. */ 471 if (val != 0x01a10000) { 472 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 473 "corrupt arc tag (0x%08x)\n", 474 filename, val); 475 return; 476 } 477 478 val = read_32bit_value(); 479 if (val == (uint32_t)-1 || val / 2 != num_counters) { 480 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 481 "mismatched number of counters (%d)\n", 482 filename, val); 483 return; 484 } 485 486 old_ctrs = malloc(sizeof(uint64_t) * num_counters); 487 for (i = 0; i < num_counters; ++i) 488 old_ctrs[i] = read_64bit_value(); 489 } 490 491 cur_pos = save_cur_pos; 492 493 /* Counter #1 (arcs) tag */ 494 write_bytes("\0\0\xa1\1", 4); 495 write_32bit_value(num_counters * 2); 496 for (i = 0; i < num_counters; ++i) { 497 counters[i] += (old_ctrs ? old_ctrs[i] : 0); 498 write_64bit_value(counters[i]); 499 } 500 501 free(old_ctrs); 502 503 #ifdef DEBUG_GCDAPROFILING 504 fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 505 for (i = 0; i < num_counters; ++i) 506 fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 507 #endif 508 } 509 510 COMPILER_RT_VISIBILITY 511 void llvm_gcda_summary_info() { 512 const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ 513 uint32_t i; 514 uint32_t runs = 1; 515 static uint32_t run_counted = 0; // We only want to increase the run count once. 516 uint32_t val = 0; 517 uint64_t save_cur_pos = cur_pos; 518 519 if (!output_file) return; 520 521 val = read_le_32bit_value(); 522 523 if (val != (uint32_t)-1) { 524 /* There are counters present in the file. Merge them. */ 525 if (val != 0xa1000000) { 526 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 527 "corrupt object tag (0x%08x)\n", 528 filename, val); 529 return; 530 } 531 532 val = read_32bit_value(); /* length */ 533 if (val != obj_summary_len) { 534 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 535 "mismatched object length (%d)\n", 536 filename, val); 537 return; 538 } 539 540 read_32bit_value(); /* checksum, unused */ 541 read_32bit_value(); /* num, unused */ 542 uint32_t prev_runs = read_32bit_value(); 543 /* Add previous run count to new counter, if not already counted before. */ 544 runs = run_counted ? prev_runs : prev_runs + 1; 545 } 546 547 cur_pos = save_cur_pos; 548 549 /* Object summary tag */ 550 write_bytes("\0\0\0\xa1", 4); 551 write_32bit_value(obj_summary_len); 552 write_32bit_value(0); /* checksum, unused */ 553 write_32bit_value(0); /* num, unused */ 554 write_32bit_value(runs); 555 for (i = 3; i < obj_summary_len; ++i) 556 write_32bit_value(0); 557 558 /* Program summary tag */ 559 write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ 560 write_32bit_value(0); /* 0 length */ 561 562 run_counted = 1; 563 564 #ifdef DEBUG_GCDAPROFILING 565 fprintf(stderr, "llvmgcda: %u runs\n", runs); 566 #endif 567 } 568 569 COMPILER_RT_VISIBILITY 570 void llvm_gcda_end_file() { 571 /* Write out EOF record. */ 572 if (output_file) { 573 write_bytes("\0\0\0\0\0\0\0\0", 8); 574 575 if (new_file) { 576 fwrite(write_buffer, cur_pos, 1, output_file); 577 free(write_buffer); 578 } else { 579 unmap_file(); 580 } 581 582 fflush(output_file); 583 lprofUnlockFd(fd); 584 fclose(output_file); 585 output_file = NULL; 586 write_buffer = NULL; 587 } 588 free(filename); 589 590 #ifdef DEBUG_GCDAPROFILING 591 fprintf(stderr, "llvmgcda: -----\n"); 592 #endif 593 } 594 595 COMPILER_RT_VISIBILITY 596 void llvm_register_writeout_function(fn_ptr fn) { 597 fn_list_insert(&writeout_fn_list, fn); 598 } 599 600 COMPILER_RT_VISIBILITY 601 void llvm_writeout_files(void) { 602 struct fn_node *curr = writeout_fn_list.head; 603 604 while (curr) { 605 if (curr->id == CURRENT_ID) { 606 curr->fn(); 607 } 608 curr = curr->next; 609 } 610 } 611 612 COMPILER_RT_VISIBILITY 613 void llvm_delete_writeout_function_list(void) { 614 fn_list_remove(&writeout_fn_list); 615 } 616 617 COMPILER_RT_VISIBILITY 618 void llvm_register_flush_function(fn_ptr fn) { 619 fn_list_insert(&flush_fn_list, fn); 620 } 621 622 void __gcov_flush() { 623 struct fn_node* curr = flush_fn_list.head; 624 625 while (curr) { 626 curr->fn(); 627 curr = curr->next; 628 } 629 } 630 631 COMPILER_RT_VISIBILITY 632 void llvm_delete_flush_function_list(void) { 633 fn_list_remove(&flush_fn_list); 634 } 635 636 COMPILER_RT_VISIBILITY 637 void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn) { 638 static int atexit_ran = 0; 639 640 if (wfn) 641 llvm_register_writeout_function(wfn); 642 643 if (ffn) 644 llvm_register_flush_function(ffn); 645 646 if (atexit_ran == 0) { 647 atexit_ran = 1; 648 649 /* Make sure we write out the data and delete the data structures. */ 650 atexit(llvm_delete_flush_function_list); 651 atexit(llvm_delete_writeout_function_list); 652 atexit(llvm_writeout_files); 653 } 654 } 655 656 #endif 657