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 /* 46 * The current file we're outputting. 47 */ 48 static FILE *output_file = NULL; 49 50 /* 51 * A list of flush functions that our __gcov_flush() function should call. 52 */ 53 typedef void (*flush_fn)(); 54 55 struct flush_fn_node { 56 flush_fn fn; 57 struct flush_fn_node *next; 58 }; 59 60 struct flush_fn_node *flush_fn_head = NULL; 61 struct flush_fn_node *flush_fn_tail = NULL; 62 63 static void write_int32(uint32_t i) { 64 fwrite(&i, 4, 1, output_file); 65 } 66 67 static void write_int64(uint64_t i) { 68 uint32_t lo = i >> 0; 69 uint32_t hi = i >> 32; 70 write_int32(lo); 71 write_int32(hi); 72 } 73 74 static uint32_t length_of_string(const char *s) { 75 return (strlen(s) / 4) + 1; 76 } 77 78 static void write_string(const char *s) { 79 uint32_t len = length_of_string(s); 80 write_int32(len); 81 fwrite(s, strlen(s), 1, output_file); 82 fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file); 83 } 84 85 static uint32_t read_int32() { 86 uint32_t tmp; 87 88 if (fread(&tmp, 1, 4, output_file) != 4) 89 return (uint32_t)-1; 90 91 return tmp; 92 } 93 94 static uint64_t read_int64() { 95 uint64_t tmp; 96 97 if (fread(&tmp, 1, 8, output_file) != 8) 98 return (uint64_t)-1; 99 100 return tmp; 101 } 102 103 static char *mangle_filename(const char *orig_filename) { 104 char *filename = 0; 105 int prefix_len = 0; 106 int prefix_strip = 0; 107 int level = 0; 108 const char *fname = orig_filename, *ptr = NULL; 109 const char *prefix = getenv("GCOV_PREFIX"); 110 const char *tmp = getenv("GCOV_PREFIX_STRIP"); 111 112 if (!prefix) 113 return strdup(orig_filename); 114 115 if (tmp) { 116 prefix_strip = atoi(tmp); 117 118 /* Negative GCOV_PREFIX_STRIP values are ignored */ 119 if (prefix_strip < 0) 120 prefix_strip = 0; 121 } 122 123 prefix_len = strlen(prefix); 124 filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1); 125 strcpy(filename, prefix); 126 127 if (prefix[prefix_len - 1] != '/') 128 strcat(filename, "/"); 129 130 for (ptr = fname + 1; *ptr != '\0' && level < prefix_strip; ++ptr) { 131 if (*ptr != '/') continue; 132 fname = ptr; 133 ++level; 134 } 135 136 strcat(filename, fname); 137 138 return filename; 139 } 140 141 static void recursive_mkdir(char *filename) { 142 int i; 143 144 for (i = 1; filename[i] != '\0'; ++i) { 145 if (filename[i] != '/') continue; 146 filename[i] = '\0'; 147 #ifdef _WIN32 148 _mkdir(filename); 149 #else 150 mkdir(filename, 0755); /* Some of these will fail, ignore it. */ 151 #endif 152 filename[i] = '/'; 153 } 154 } 155 156 /* 157 * --- LLVM line counter API --- 158 */ 159 160 /* A file in this case is a translation unit. Each .o file built with line 161 * profiling enabled will emit to a different file. Only one file may be 162 * started at a time. 163 */ 164 void llvm_gcda_start_file(const char *orig_filename, const char version[4]) { 165 char *filename = mangle_filename(orig_filename); 166 167 /* Try just opening the file. */ 168 output_file = fopen(filename, "r+b"); 169 170 if (!output_file) { 171 /* Try opening the file, creating it if necessary. */ 172 output_file = fopen(filename, "w+b"); 173 if (!output_file) { 174 /* Try creating the directories first then opening the file. */ 175 recursive_mkdir(filename); 176 output_file = fopen(filename, "w+b"); 177 if (!output_file) { 178 /* Bah! It's hopeless. */ 179 fprintf(stderr, "profiling:%s: cannot open\n", filename); 180 free(filename); 181 return; 182 } 183 } 184 } 185 186 /* gcda file, version, stamp LLVM. */ 187 fwrite("adcg", 4, 1, output_file); 188 fwrite(version, 4, 1, output_file); 189 fwrite("MVLL", 4, 1, output_file); 190 free(filename); 191 192 #ifdef DEBUG_GCDAPROFILING 193 fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 194 #endif 195 } 196 197 /* Given an array of pointers to counters (counters), increment the n-th one, 198 * where we're also given a pointer to n (predecessor). 199 */ 200 void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 201 uint64_t **counters) { 202 uint64_t *counter; 203 uint32_t pred; 204 205 pred = *predecessor; 206 if (pred == 0xffffffff) 207 return; 208 counter = counters[pred]; 209 210 /* Don't crash if the pred# is out of sync. This can happen due to threads, 211 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 212 if (counter) 213 ++*counter; 214 #ifdef DEBUG_GCDAPROFILING 215 else 216 fprintf(stderr, 217 "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 218 *counter, *predecessor); 219 #endif 220 } 221 222 void llvm_gcda_emit_function(uint32_t ident, const char *function_name, 223 uint8_t use_extra_checksum) { 224 uint32_t len = 2; 225 if (use_extra_checksum) 226 len++; 227 #ifdef DEBUG_GCDAPROFILING 228 fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 229 function_name ? function_name : "NULL"); 230 #endif 231 if (!output_file) return; 232 233 /* function tag */ 234 fwrite("\0\0\0\1", 4, 1, output_file); 235 if (function_name) 236 len += 1 + length_of_string(function_name); 237 write_int32(len); 238 write_int32(ident); 239 write_int32(0); 240 if (use_extra_checksum) 241 write_int32(0); 242 if (function_name) 243 write_string(function_name); 244 } 245 246 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 247 uint32_t i; 248 uint64_t *old_ctrs = NULL; 249 uint32_t val = 0; 250 long pos = 0; 251 252 if (!output_file) return; 253 254 pos = ftell(output_file); 255 val = read_int32(); 256 257 if (val != (uint32_t)-1) { 258 /* There are counters present in the file. Merge them. */ 259 uint32_t j; 260 261 if (val != 0x01a10000) { 262 fprintf(stderr, "profiling: invalid magic number (0x%08x)\n", val); 263 return; 264 } 265 266 val = read_int32(); 267 if (val == (uint32_t)-1 || val / 2 != num_counters) { 268 fprintf(stderr, "profiling: invalid number of counters (%d)\n", val); 269 return; 270 } 271 272 old_ctrs = malloc(sizeof(uint64_t) * num_counters); 273 274 for (j = 0; j < num_counters; ++j) 275 old_ctrs[j] = read_int64(); 276 } 277 278 /* Reset for writing. */ 279 fseek(output_file, pos, SEEK_SET); 280 281 /* Counter #1 (arcs) tag */ 282 fwrite("\0\0\xa1\1", 4, 1, output_file); 283 write_int32(num_counters * 2); 284 for (i = 0; i < num_counters; ++i) 285 write_int64(counters[i] + (old_ctrs ? old_ctrs[i] : 0)); 286 287 free(old_ctrs); 288 289 #ifdef DEBUG_GCDAPROFILING 290 fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 291 for (i = 0; i < num_counters; ++i) 292 fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 293 #endif 294 } 295 296 void llvm_gcda_end_file() { 297 /* Write out EOF record. */ 298 if (!output_file) return; 299 fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file); 300 fclose(output_file); 301 output_file = NULL; 302 303 #ifdef DEBUG_GCDAPROFILING 304 fprintf(stderr, "llvmgcda: -----\n"); 305 #endif 306 } 307 308 void llvm_register_flush_function(flush_fn fn) { 309 struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); 310 new_node->fn = fn; 311 new_node->next = NULL; 312 313 if (!flush_fn_head) { 314 flush_fn_head = flush_fn_tail = new_node; 315 } else { 316 flush_fn_tail->next = new_node; 317 flush_fn_tail = new_node; 318 } 319 } 320 321 void __gcov_flush() { 322 struct flush_fn_node *curr = flush_fn_head; 323 324 while (curr) { 325 curr->fn(); 326 curr = curr->next; 327 } 328 } 329 330 void llvm_delete_flush_function_list() { 331 while (flush_fn_head) { 332 struct flush_fn_node *node = flush_fn_head; 333 flush_fn_head = flush_fn_head->next; 334 free(node); 335 } 336 337 flush_fn_head = flush_fn_tail = NULL; 338 } 339