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