GCDAProfiling.c revision 276851
1103856Stjr/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ 2103856Stjr|* 3103856Stjr|* The LLVM Compiler Infrastructure 4103856Stjr|* 5103856Stjr|* This file is distributed under the University of Illinois Open Source 6103856Stjr|* License. See LICENSE.TXT for details. 7103856Stjr|* 8103856Stjr|*===----------------------------------------------------------------------===*| 9103856Stjr|* 10103856Stjr|* This file implements the call back routines for the gcov profiling 11103856Stjr|* instrumentation pass. Link against this library when running code through 12103856Stjr|* the -insert-gcov-profiling LLVM pass. 13103856Stjr|* 14103856Stjr|* We emit files in a corrupt version of GCOV's "gcda" file format. These files 15103856Stjr|* are only close enough that LCOV will happily parse them. Anything that lcov 16103856Stjr|* ignores is missing. 17103856Stjr|* 18103856Stjr|* TODO: gcov is multi-process safe by having each exit open the existing file 19103856Stjr|* and append to it. We'd like to achieve that and be thread-safe too. 20103856Stjr|* 21103856Stjr\*===----------------------------------------------------------------------===*/ 22103856Stjr 23103856Stjr#include <errno.h> 24103856Stjr#include <fcntl.h> 25103856Stjr#include <stdio.h> 26103856Stjr#include <stdlib.h> 27103856Stjr#include <string.h> 28103856Stjr#include <sys/mman.h> 29103856Stjr#ifdef _WIN32 30103856Stjr#include <direct.h> 31103856Stjr#endif 32103856Stjr 33103856Stjr#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) 34103856Stjr 35103856Stjr#if !I386_FREEBSD 36103856Stjr#include <sys/stat.h> 37103856Stjr#include <sys/types.h> 38128844Sobrien#endif 39103856Stjr 40103856Stjr#if !defined(_MSC_VER) && !I386_FREEBSD 41103856Stjr#include <stdint.h> 42103856Stjr#endif 43103856Stjr 44149313Sstefanf#if defined(_MSC_VER) 45103856Stjrtypedef unsigned int uint32_t; 46103856Stjrtypedef unsigned long long uint64_t; 47103856Stjr#elif I386_FREEBSD 48103856Stjr/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to 49103856Stjr * FreeBSD 10, r232261) when compiled in 32-bit mode. 50103856Stjr */ 51103856Stjrtypedef unsigned char uint8_t; 52103856Stjrtypedef unsigned int uint32_t; 53103856Stjrtypedef unsigned long long uint64_t; 54103856Stjrint mkdir(const char*, unsigned short); 55103856Stjr#endif 56103856Stjr 57128822Sdas/* #define DEBUG_GCDAPROFILING */ 58103856Stjr 59103856Stjr/* 60103856Stjr * --- GCOV file format I/O primitives --- 61103856Stjr */ 62103856Stjr 63103856Stjr/* 64103856Stjr * The current file name we're outputting. Used primarily for error logging. 65103856Stjr */ 66103856Stjrstatic char *filename = NULL; 67103856Stjr 68103856Stjr/* 69103856Stjr * The current file we're outputting. 70103856Stjr */ 71103856Stjrstatic FILE *output_file = NULL; 72103856Stjr 73103856Stjr/* 74103856Stjr * Buffer that we write things into. 75103856Stjr */ 76103856Stjr#define WRITE_BUFFER_SIZE (128 * 1024) 77103856Stjrstatic char *write_buffer = NULL; 78103856Stjrstatic uint64_t cur_buffer_size = 0; 79103856Stjrstatic uint64_t cur_pos = 0; 80117249Stjrstatic uint64_t file_size = 0; 81117249Stjrstatic int new_file = 0; 82103856Stjrstatic int fd = -1; 83103856Stjr 84103856Stjr/* 85103856Stjr * A list of functions to write out the data. 86103856Stjr */ 87125283Sdastypedef void (*writeout_fn)(); 88103856Stjr 89103856Stjrstruct writeout_fn_node { 90103856Stjr writeout_fn fn; 91103856Stjr struct writeout_fn_node *next; 92103856Stjr}; 93103856Stjr 94103856Stjrstatic struct writeout_fn_node *writeout_fn_head = NULL; 95103856Stjrstatic struct writeout_fn_node *writeout_fn_tail = NULL; 96103856Stjr 97103856Stjr/* 98157381Sphk * A list of flush functions that our __gcov_flush() function should call. 99117249Stjr */ 100157381Sphktypedef void (*flush_fn)(); 101117249Stjr 102103856Stjrstruct flush_fn_node { 103103856Stjr flush_fn fn; 104103856Stjr struct flush_fn_node *next; 105103856Stjr}; 106187422Sdas 107187422Sdasstatic struct flush_fn_node *flush_fn_head = NULL; 108103856Stjrstatic struct flush_fn_node *flush_fn_tail = NULL; 109103856Stjr 110103856Stjrstatic void resize_write_buffer(uint64_t size) { 111103856Stjr if (!new_file) return; 112103856Stjr size += cur_pos; 113103856Stjr if (size <= cur_buffer_size) return; 114103856Stjr size = (size - 1) / WRITE_BUFFER_SIZE + 1; 115103856Stjr size *= WRITE_BUFFER_SIZE; 116103856Stjr write_buffer = realloc(write_buffer, size); 117103856Stjr cur_buffer_size = size; 118103856Stjr} 119103856Stjr 120103856Stjrstatic void write_bytes(const char *s, size_t len) { 121103856Stjr resize_write_buffer(len); 122103856Stjr memcpy(&write_buffer[cur_pos], s, len); 123103856Stjr cur_pos += len; 124103856Stjr} 125103856Stjr 126103856Stjrstatic void write_32bit_value(uint32_t i) { 127103856Stjr write_bytes((char*)&i, 4); 128103856Stjr} 129103856Stjr 130103856Stjrstatic void write_64bit_value(uint64_t i) { 131103856Stjr write_bytes((char*)&i, 8); 132103856Stjr} 133103856Stjr 134103856Stjrstatic uint32_t length_of_string(const char *s) { 135103856Stjr return (strlen(s) / 4) + 1; 136103856Stjr} 137103856Stjr 138103856Stjrstatic void write_string(const char *s) { 139103856Stjr uint32_t len = length_of_string(s); 140103856Stjr write_32bit_value(len); 141103856Stjr write_bytes(s, strlen(s)); 142103856Stjr write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); 143103856Stjr} 144103856Stjr 145103856Stjrstatic uint32_t read_32bit_value() { 146105317Stjr uint32_t val; 147128002Stjr 148103856Stjr if (new_file) 149103856Stjr return (uint32_t)-1; 150103856Stjr 151103856Stjr val = *(uint32_t*)&write_buffer[cur_pos]; 152103856Stjr cur_pos += 4; 153103856Stjr return val; 154103856Stjr} 155103856Stjr 156103856Stjrstatic uint64_t read_64bit_value() { 157103856Stjr uint64_t val; 158103856Stjr 159103856Stjr if (new_file) 160103856Stjr return (uint64_t)-1; 161103856Stjr 162103856Stjr val = *(uint64_t*)&write_buffer[cur_pos]; 163103856Stjr cur_pos += 8; 164103856Stjr return val; 165103856Stjr} 166103856Stjr 167103856Stjrstatic char *mangle_filename(const char *orig_filename) { 168103856Stjr char *new_filename; 169103856Stjr size_t filename_len, prefix_len; 170103856Stjr int prefix_strip; 171103856Stjr int level = 0; 172103856Stjr const char *fname, *ptr; 173103856Stjr const char *prefix = getenv("GCOV_PREFIX"); 174103856Stjr const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP"); 175103856Stjr 176103856Stjr if (prefix == NULL || prefix[0] == '\0') 177103856Stjr return strdup(orig_filename); 178103856Stjr 179103856Stjr if (prefix_strip_str) { 180103856Stjr prefix_strip = atoi(prefix_strip_str); 181103856Stjr 182103856Stjr /* Negative GCOV_PREFIX_STRIP values are ignored */ 183103856Stjr if (prefix_strip < 0) 184103856Stjr prefix_strip = 0; 185103856Stjr } else { 186103856Stjr prefix_strip = 0; 187103856Stjr } 188103856Stjr 189103856Stjr fname = orig_filename; 190103856Stjr for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) { 191103856Stjr if (*ptr == '\0') 192103856Stjr break; 193103856Stjr if (*ptr != '/') 194103856Stjr continue; 195103856Stjr fname = ptr; 196103856Stjr ++level; 197103856Stjr } 198103856Stjr 199103856Stjr filename_len = strlen(fname); 200103856Stjr prefix_len = strlen(prefix); 201103856Stjr new_filename = malloc(prefix_len + 1 + filename_len + 1); 202103856Stjr memcpy(new_filename, prefix, prefix_len); 203103856Stjr 204103856Stjr if (prefix[prefix_len - 1] != '/') 205103856Stjr new_filename[prefix_len++] = '/'; 206103856Stjr memcpy(new_filename + prefix_len, fname, filename_len + 1); 207103856Stjr 208103856Stjr return new_filename; 209103856Stjr} 210103856Stjr 211103856Stjrstatic void recursive_mkdir(char *path) { 212103856Stjr int i; 213103856Stjr 214103856Stjr for (i = 1; path[i] != '\0'; ++i) { 215103856Stjr if (path[i] != '/') continue; 216103856Stjr path[i] = '\0'; 217103856Stjr#ifdef _WIN32 218103856Stjr _mkdir(path); 219103856Stjr#else 220103856Stjr mkdir(path, 0755); /* Some of these will fail, ignore it. */ 221103856Stjr#endif 222103856Stjr path[i] = '/'; 223103856Stjr } 224103856Stjr} 225103856Stjr 226103856Stjrstatic int map_file() { 227103856Stjr fseek(output_file, 0L, SEEK_END); 228103856Stjr file_size = ftell(output_file); 229103856Stjr 230103856Stjr /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an 231103856Stjr * error message because it should "just work" for the user. */ 232103856Stjr if (file_size == 0) 233103856Stjr return -1; 234103856Stjr 235103856Stjr write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, 236103856Stjr MAP_FILE | MAP_SHARED, fd, 0); 237103856Stjr if (write_buffer == (void *)-1) { 238103856Stjr int errnum = errno; 239103856Stjr fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, 240103856Stjr strerror(errnum)); 241103856Stjr return -1; 242103856Stjr } 243103856Stjr return 0; 244103856Stjr} 245103856Stjr 246103856Stjrstatic void unmap_file() { 247103856Stjr if (msync(write_buffer, file_size, MS_SYNC) == -1) { 248103856Stjr int errnum = errno; 249103856Stjr fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, 250103856Stjr strerror(errnum)); 251103856Stjr } 252103856Stjr 253103856Stjr /* We explicitly ignore errors from unmapping because at this point the data 254103856Stjr * is written and we don't care. 255103856Stjr */ 256103856Stjr (void)munmap(write_buffer, file_size); 257103856Stjr write_buffer = NULL; 258103856Stjr file_size = 0; 259103856Stjr} 260103856Stjr 261128822Sdas/* 262117249Stjr * --- LLVM line counter API --- 263117249Stjr */ 264103856Stjr 265103856Stjr/* A file in this case is a translation unit. Each .o file built with line 266103856Stjr * profiling enabled will emit to a different file. Only one file may be 267103856Stjr * started at a time. 268103856Stjr */ 269103856Stjrvoid llvm_gcda_start_file(const char *orig_filename, const char version[4], 270103856Stjr uint32_t checksum) { 271103856Stjr const char *mode = "r+b"; 272103856Stjr filename = mangle_filename(orig_filename); 273103856Stjr 274103856Stjr /* Try just opening the file. */ 275103856Stjr new_file = 0; 276103856Stjr fd = open(filename, O_RDWR); 277103856Stjr 278103856Stjr if (fd == -1) { 279103856Stjr /* Try opening the file, creating it if necessary. */ 280103856Stjr new_file = 1; 281103856Stjr mode = "w+b"; 282103856Stjr fd = open(filename, O_RDWR | O_CREAT, 0644); 283103856Stjr if (fd == -1) { 284103856Stjr /* Try creating the directories first then opening the file. */ 285103856Stjr recursive_mkdir(filename); 286103856Stjr fd = open(filename, O_RDWR | O_CREAT, 0644); 287103856Stjr if (fd == -1) { 288103856Stjr /* Bah! It's hopeless. */ 289103856Stjr int errnum = errno; 290103856Stjr fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, 291103856Stjr strerror(errnum)); 292103856Stjr return; 293103856Stjr } 294103856Stjr } 295103856Stjr } 296103856Stjr 297103856Stjr output_file = fdopen(fd, mode); 298103856Stjr 299103856Stjr /* Initialize the write buffer. */ 300103856Stjr write_buffer = NULL; 301103856Stjr cur_buffer_size = 0; 302103856Stjr cur_pos = 0; 303103856Stjr 304103856Stjr if (new_file) { 305103856Stjr resize_write_buffer(WRITE_BUFFER_SIZE); 306103856Stjr memset(write_buffer, 0, WRITE_BUFFER_SIZE); 307103856Stjr } else { 308103856Stjr if (map_file() == -1) { 309103856Stjr /* mmap failed, try to recover by clobbering */ 310103856Stjr new_file = 1; 311103856Stjr write_buffer = NULL; 312103856Stjr cur_buffer_size = 0; 313103856Stjr resize_write_buffer(WRITE_BUFFER_SIZE); 314103856Stjr memset(write_buffer, 0, WRITE_BUFFER_SIZE); 315103856Stjr } 316103856Stjr } 317103856Stjr 318103856Stjr /* gcda file, version, stamp checksum. */ 319103856Stjr write_bytes("adcg", 4); 320103856Stjr write_bytes(version, 4); 321103856Stjr write_32bit_value(checksum); 322103856Stjr 323103856Stjr#ifdef DEBUG_GCDAPROFILING 324103856Stjr fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 325103856Stjr#endif 326103856Stjr} 327103856Stjr 328103856Stjr/* Given an array of pointers to counters (counters), increment the n-th one, 329103856Stjr * where we're also given a pointer to n (predecessor). 330103856Stjr */ 331103856Stjrvoid llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 332103856Stjr uint64_t **counters) { 333103856Stjr uint64_t *counter; 334103856Stjr uint32_t pred; 335103856Stjr 336103856Stjr pred = *predecessor; 337103856Stjr if (pred == 0xffffffff) 338103856Stjr return; 339103856Stjr counter = counters[pred]; 340103856Stjr 341103856Stjr /* Don't crash if the pred# is out of sync. This can happen due to threads, 342103856Stjr or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 343103856Stjr if (counter) 344103856Stjr ++*counter; 345103856Stjr#ifdef DEBUG_GCDAPROFILING 346103856Stjr else 347103856Stjr fprintf(stderr, 348103856Stjr "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 349103856Stjr *counter, *predecessor); 350103856Stjr#endif 351103856Stjr} 352103856Stjr 353103856Stjrvoid llvm_gcda_emit_function(uint32_t ident, const char *function_name, 354103856Stjr uint32_t func_checksum, uint8_t use_extra_checksum, 355103856Stjr uint32_t cfg_checksum) { 356103856Stjr uint32_t len = 2; 357103856Stjr 358103856Stjr if (use_extra_checksum) 359103856Stjr len++; 360105317Stjr#ifdef DEBUG_GCDAPROFILING 361105317Stjr fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 362105317Stjr function_name ? function_name : "NULL"); 363103856Stjr#endif 364103856Stjr if (!output_file) return; 365103856Stjr 366105317Stjr /* function tag */ 367105317Stjr write_bytes("\0\0\0\1", 4); 368103856Stjr if (function_name) 369103856Stjr len += 1 + length_of_string(function_name); 370103856Stjr write_32bit_value(len); 371103856Stjr write_32bit_value(ident); 372103856Stjr write_32bit_value(func_checksum); 373105317Stjr if (use_extra_checksum) 374105317Stjr write_32bit_value(cfg_checksum); 375103856Stjr if (function_name) 376105317Stjr write_string(function_name); 377105317Stjr} 378103856Stjr 379187422Sdasvoid llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 380105317Stjr uint32_t i; 381103856Stjr uint64_t *old_ctrs = NULL; 382105317Stjr uint32_t val = 0; 383105317Stjr uint64_t save_cur_pos = cur_pos; 384128002Stjr 385105317Stjr if (!output_file) return; 386105317Stjr 387105317Stjr val = read_32bit_value(); 388105317Stjr 389128002Stjr if (val != (uint32_t)-1) { 390105317Stjr /* There are counters present in the file. Merge them. */ 391105317Stjr if (val != 0x01a10000) { 392105317Stjr fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 393105317Stjr "corrupt arc tag (0x%08x)\n", 394105317Stjr filename, val); 395105317Stjr return; 396105317Stjr } 397105317Stjr 398105317Stjr val = read_32bit_value(); 399105317Stjr if (val == (uint32_t)-1 || val / 2 != num_counters) { 400105317Stjr fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 401105317Stjr "mismatched number of counters (%d)\n", 402105317Stjr filename, val); 403103856Stjr return; 404103856Stjr } 405103856Stjr 406103856Stjr old_ctrs = malloc(sizeof(uint64_t) * num_counters); 407103856Stjr for (i = 0; i < num_counters; ++i) 408105317Stjr old_ctrs[i] = read_64bit_value(); 409105317Stjr } 410103856Stjr 411103856Stjr cur_pos = save_cur_pos; 412103856Stjr 413103856Stjr /* Counter #1 (arcs) tag */ 414103856Stjr write_bytes("\0\0\xa1\1", 4); 415103856Stjr write_32bit_value(num_counters * 2); 416103856Stjr for (i = 0; i < num_counters; ++i) { 417103856Stjr counters[i] += (old_ctrs ? old_ctrs[i] : 0); 418103856Stjr write_64bit_value(counters[i]); 419105317Stjr } 420103856Stjr 421103856Stjr free(old_ctrs); 422103856Stjr 423103856Stjr#ifdef DEBUG_GCDAPROFILING 424103856Stjr fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 425103856Stjr for (i = 0; i < num_counters; ++i) 426103856Stjr fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 427103856Stjr#endif 428103856Stjr} 429103856Stjr 430103856Stjrvoid llvm_gcda_summary_info() { 431103856Stjr const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ 432103856Stjr uint32_t i; 433103856Stjr uint32_t runs = 1; 434103856Stjr uint32_t val = 0; 435103856Stjr uint64_t save_cur_pos = cur_pos; 436103856Stjr 437103856Stjr if (!output_file) return; 438103856Stjr 439103856Stjr val = read_32bit_value(); 440103856Stjr 441105317Stjr if (val != (uint32_t)-1) { 442105317Stjr /* There are counters present in the file. Merge them. */ 443103856Stjr if (val != 0xa1000000) { 444187422Sdas fprintf(stderr, "profiling: %s: cannot merge previous run count: " 445103856Stjr "corrupt object tag (0x%08x)\n", 446105317Stjr filename, val); 447105317Stjr return; 448105317Stjr } 449128002Stjr 450105317Stjr val = read_32bit_value(); /* length */ 451105317Stjr if (val != obj_summary_len) { 452105317Stjr fprintf(stderr, "profiling: %s: cannot merge previous run count: " 453105317Stjr "mismatched object length (%d)\n", 454128002Stjr filename, val); 455105317Stjr return; 456105317Stjr } 457105317Stjr 458105317Stjr read_32bit_value(); /* checksum, unused */ 459105317Stjr read_32bit_value(); /* num, unused */ 460105317Stjr runs += read_32bit_value(); /* Add previous run count to new counter. */ 461105317Stjr } 462105317Stjr 463105317Stjr cur_pos = save_cur_pos; 464105317Stjr 465105317Stjr /* Object summary tag */ 466103856Stjr write_bytes("\0\0\0\xa1", 4); 467103856Stjr write_32bit_value(obj_summary_len); 468103856Stjr write_32bit_value(0); /* checksum, unused */ 469103856Stjr write_32bit_value(0); /* num, unused */ 470105317Stjr write_32bit_value(runs); 471105317Stjr for (i = 3; i < obj_summary_len; ++i) 472105317Stjr write_32bit_value(0); 473105317Stjr 474103856Stjr /* Program summary tag */ 475103856Stjr write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ 476103856Stjr write_32bit_value(0); /* 0 length */ 477103856Stjr 478103856Stjr#ifdef DEBUG_GCDAPROFILING 479103856Stjr fprintf(stderr, "llvmgcda: %u runs\n", runs); 480103856Stjr#endif 481103856Stjr} 482103856Stjr 483105317Stjrvoid llvm_gcda_end_file() { 484103856Stjr /* Write out EOF record. */ 485103856Stjr if (output_file) { 486103856Stjr write_bytes("\0\0\0\0\0\0\0\0", 8); 487103856Stjr 488103856Stjr if (new_file) { 489103856Stjr fwrite(write_buffer, cur_pos, 1, output_file); 490103856Stjr free(write_buffer); 491103856Stjr } else { 492103856Stjr unmap_file(); 493103856Stjr } 494103856Stjr 495103856Stjr fclose(output_file); 496103856Stjr output_file = NULL; 497103856Stjr write_buffer = NULL; 498103856Stjr } 499103856Stjr free(filename); 500103856Stjr 501103856Stjr#ifdef DEBUG_GCDAPROFILING 502103856Stjr fprintf(stderr, "llvmgcda: -----\n"); 503105317Stjr#endif 504105317Stjr} 505187422Sdas 506103856Stjrvoid llvm_register_writeout_function(writeout_fn fn) { 507105317Stjr struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); 508103856Stjr new_node->fn = fn; 509105317Stjr new_node->next = NULL; 510105317Stjr 511128002Stjr if (!writeout_fn_head) { 512105317Stjr writeout_fn_head = writeout_fn_tail = new_node; 513105317Stjr } else { 514105317Stjr writeout_fn_tail->next = new_node; 515105317Stjr writeout_fn_tail = new_node; 516128002Stjr } 517105317Stjr} 518105317Stjr 519105317Stjrvoid llvm_writeout_files() { 520105317Stjr struct writeout_fn_node *curr = writeout_fn_head; 521105317Stjr 522105317Stjr while (curr) { 523105317Stjr curr->fn(); 524105317Stjr curr = curr->next; 525105317Stjr } 526105317Stjr} 527105317Stjr 528103856Stjrvoid llvm_delete_writeout_function_list() { 529103856Stjr while (writeout_fn_head) { 530103856Stjr struct writeout_fn_node *node = writeout_fn_head; 531103856Stjr writeout_fn_head = writeout_fn_head->next; 532105317Stjr free(node); 533105317Stjr } 534105317Stjr 535105317Stjr writeout_fn_head = writeout_fn_tail = NULL; 536103856Stjr} 537103856Stjr 538103856Stjrvoid llvm_register_flush_function(flush_fn fn) { 539103856Stjr struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); 540103856Stjr new_node->fn = fn; 541103856Stjr new_node->next = NULL; 542117250Stjr 543117250Stjr if (!flush_fn_head) { 544117250Stjr flush_fn_head = flush_fn_tail = new_node; 545103856Stjr } else { 546103856Stjr flush_fn_tail->next = new_node; 547103856Stjr flush_fn_tail = new_node; 548103856Stjr } 549103856Stjr} 550103856Stjr 551103856Stjrvoid __gcov_flush() { 552103856Stjr struct flush_fn_node *curr = flush_fn_head; 553103856Stjr 554103856Stjr while (curr) { 555103856Stjr curr->fn(); 556103856Stjr curr = curr->next; 557103856Stjr } 558103856Stjr} 559103856Stjr 560103856Stjrvoid llvm_delete_flush_function_list() { 561103856Stjr while (flush_fn_head) { 562103856Stjr struct flush_fn_node *node = flush_fn_head; 563103856Stjr flush_fn_head = flush_fn_head->next; 564103856Stjr free(node); 565103856Stjr } 566103856Stjr 567103856Stjr flush_fn_head = flush_fn_tail = NULL; 568103856Stjr} 569103856Stjr 570103856Stjrvoid llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { 571103856Stjr static int atexit_ran = 0; 572103856Stjr 573103856Stjr if (wfn) 574103856Stjr llvm_register_writeout_function(wfn); 575103856Stjr 576103856Stjr if (ffn) 577103856Stjr llvm_register_flush_function(ffn); 578103856Stjr 579103856Stjr if (atexit_ran == 0) { 580103856Stjr atexit_ran = 1; 581103856Stjr 582103856Stjr /* Make sure we write out the data and delete the data structures. */ 583103856Stjr atexit(llvm_delete_flush_function_list); 584103856Stjr atexit(llvm_delete_writeout_function_list); 585103856Stjr atexit(llvm_writeout_files); 586103856Stjr } 587103856Stjr} 588103856Stjr