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