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 #include "llvm/Support/DataTypes.h" 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #ifdef _WIN32 30 #include <direct.h> 31 #endif 32 33 /* #define DEBUG_GCDAPROFILING */ 34 35 /* 36 * --- GCOV file format I/O primitives --- 37 */ 38 39 static FILE *output_file = NULL; 40 41 static void write_int32(uint32_t i) { 42 fwrite(&i, 4, 1, output_file); 43 } 44 45 static void write_int64(uint64_t i) { 46 uint32_t lo, hi; 47 lo = i >> 0; 48 hi = i >> 32; 49 50 write_int32(lo); 51 write_int32(hi); 52 } 53 54 static uint32_t length_of_string(const char *s) { 55 return (strlen(s) / 4) + 1; 56 } 57 58 static void write_string(const char *s) { 59 uint32_t len = length_of_string(s); 60 write_int32(len); 61 fwrite(s, strlen(s), 1, output_file); 62 fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file); 63 } 64 65 static char *mangle_filename(const char *orig_filename) { 66 /* TODO: handle GCOV_PREFIX_STRIP */ 67 const char *prefix; 68 char *filename = 0; 69 70 prefix = getenv("GCOV_PREFIX"); 71 72 if (!prefix) 73 return strdup(orig_filename); 74 75 filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1); 76 strcpy(filename, prefix); 77 strcat(filename, "/"); 78 strcat(filename, orig_filename); 79 80 return filename; 81 } 82 83 static void recursive_mkdir(const char *filename) { 84 char *pathname; 85 int i, e; 86 87 for (i = 1, e = strlen(filename); i != e; ++i) { 88 if (filename[i] == '/') { 89 pathname = malloc(i + 1); 90 strncpy(pathname, filename, i); 91 pathname[i] = '\0'; 92 #ifdef _WIN32 93 _mkdir(pathname); 94 #else 95 mkdir(pathname, 0750); /* some of these will fail, ignore it. */ 96 #endif 97 free(pathname); 98 } 99 } 100 } 101 102 /* 103 * --- LLVM line counter API --- 104 */ 105 106 /* A file in this case is a translation unit. Each .o file built with line 107 * profiling enabled will emit to a different file. Only one file may be 108 * started at a time. 109 */ 110 void llvm_gcda_start_file(const char *orig_filename) { 111 char *filename; 112 filename = mangle_filename(orig_filename); 113 recursive_mkdir(filename); 114 output_file = fopen(filename, "wb"); 115 116 /* gcda file, version 404*, stamp LLVM. */ 117 #ifdef __APPLE__ 118 fwrite("adcg*204MVLL", 12, 1, output_file); 119 #else 120 fwrite("adcg*404MVLL", 12, 1, output_file); 121 #endif 122 123 #ifdef DEBUG_GCDAPROFILING 124 printf("llvmgcda: [%s]\n", orig_filename); 125 #endif 126 127 free(filename); 128 } 129 130 /* Given an array of pointers to counters (counters), increment the n-th one, 131 * where we're also given a pointer to n (predecessor). 132 */ 133 void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 134 uint64_t **counters) { 135 uint64_t *counter; 136 uint32_t pred; 137 138 pred = *predecessor; 139 if (pred == 0xffffffff) 140 return; 141 counter = counters[pred]; 142 143 /* Don't crash if the pred# is out of sync. This can happen due to threads, 144 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 145 if (counter) 146 ++*counter; 147 #ifdef DEBUG_GCDAPROFILING 148 else 149 printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n", 150 state_table_row, *predecessor); 151 #endif 152 } 153 154 void llvm_gcda_emit_function(uint32_t ident, const char *function_name) { 155 #ifdef DEBUG_GCDAPROFILING 156 printf("llvmgcda: function id=%x\n", ident); 157 #endif 158 159 /* function tag */ 160 fwrite("\0\0\0\1", 4, 1, output_file); 161 write_int32(3 + 1 + length_of_string(function_name)); 162 write_int32(ident); 163 write_int32(0); 164 write_int32(0); 165 write_string(function_name); 166 } 167 168 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 169 uint32_t i; 170 /* counter #1 (arcs) tag */ 171 fwrite("\0\0\xa1\1", 4, 1, output_file); 172 write_int32(num_counters * 2); 173 for (i = 0; i < num_counters; ++i) { 174 write_int64(counters[i]); 175 } 176 177 #ifdef DEBUG_GCDAPROFILING 178 printf("llvmgcda: %u arcs\n", num_counters); 179 for (i = 0; i < num_counters; ++i) { 180 printf("llvmgcda: %llu\n", (unsigned long long)counters[i]); 181 } 182 #endif 183 } 184 185 void llvm_gcda_end_file() { 186 /* Write out EOF record. */ 187 fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file); 188 fclose(output_file); 189 output_file = NULL; 190 191 #ifdef DEBUG_GCDAPROFILING 192 printf("llvmgcda: -----\n"); 193 #endif 194 } 195