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