1/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
2|*
3|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4|* See https://llvm.org/LICENSE.txt for license information.
5|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6|*
7|*===----------------------------------------------------------------------===*|
8|*
9|* This file implements the call back routines for the gcov profiling
10|* instrumentation pass. Link against this library when running code through
11|* the -insert-gcov-profiling LLVM pass.
12|*
13|* We emit files in a corrupt version of GCOV's "gcda" file format. These files
14|* are only close enough that LCOV will happily parse them. Anything that lcov
15|* ignores is missing.
16|*
17|* TODO: gcov is multi-process safe by having each exit open the existing file
18|* and append to it. We'd like to achieve that and be thread-safe too.
19|*
20\*===----------------------------------------------------------------------===*/
21
22#if !defined(__Fuchsia__)
23
24#include <errno.h>
25#include <fcntl.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#if defined(_WIN32)
31#define WIN32_LEAN_AND_MEAN
32#include <windows.h>
33#include "WindowsMMap.h"
34#else
35#include <sys/file.h>
36#include <sys/mman.h>
37#include <sys/types.h>
38#include <unistd.h>
39#endif
40
41#if defined(__FreeBSD__) && defined(__i386__)
42#define I386_FREEBSD 1
43#else
44#define I386_FREEBSD 0
45#endif
46
47#if !defined(_MSC_VER) && !I386_FREEBSD
48#include <stdint.h>
49#endif
50
51#if defined(_MSC_VER)
52typedef unsigned char uint8_t;
53typedef unsigned int uint32_t;
54typedef unsigned long long uint64_t;
55#elif I386_FREEBSD
56/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
57 * FreeBSD 10, r232261) when compiled in 32-bit mode.
58 */
59typedef unsigned char uint8_t;
60typedef unsigned int uint32_t;
61typedef unsigned long long uint64_t;
62#endif
63
64#include "InstrProfiling.h"
65#include "InstrProfilingUtil.h"
66
67/* #define DEBUG_GCDAPROFILING */
68
69/*
70 * --- GCOV file format I/O primitives ---
71 */
72
73/*
74 * The current file name we're outputting. Used primarily for error logging.
75 */
76static char *filename = NULL;
77
78/*
79 * The current file we're outputting.
80 */
81static FILE *output_file = NULL;
82
83/*
84 * Buffer that we write things into.
85 */
86#define WRITE_BUFFER_SIZE (128 * 1024)
87static unsigned char *write_buffer = NULL;
88static uint64_t cur_buffer_size = 0;
89static uint64_t cur_pos = 0;
90static uint64_t file_size = 0;
91static int new_file = 0;
92#if defined(_WIN32)
93static HANDLE mmap_handle = NULL;
94#endif
95static int fd = -1;
96
97typedef void (*fn_ptr)();
98
99typedef void* dynamic_object_id;
100// The address of this variable identifies a given dynamic object.
101static dynamic_object_id current_id;
102#define CURRENT_ID (&current_id)
103
104struct fn_node {
105  dynamic_object_id id;
106  fn_ptr fn;
107  struct fn_node* next;
108};
109
110struct fn_list {
111  struct fn_node *head, *tail;
112};
113
114/*
115 * A list of functions to write out the data, shared between all dynamic objects.
116 */
117struct fn_list writeout_fn_list;
118
119/*
120 *  A list of flush functions that our __gcov_flush() function should call, shared between all dynamic objects.
121 */
122struct fn_list flush_fn_list;
123
124/*
125 *  A list of reset functions, shared between all dynamic objects.
126 */
127struct fn_list reset_fn_list;
128
129static void fn_list_insert(struct fn_list* list, fn_ptr fn) {
130  struct fn_node* new_node = malloc(sizeof(struct fn_node));
131  new_node->fn = fn;
132  new_node->next = NULL;
133  new_node->id = CURRENT_ID;
134
135  if (!list->head) {
136    list->head = list->tail = new_node;
137  } else {
138    list->tail->next = new_node;
139    list->tail = new_node;
140  }
141}
142
143static void fn_list_remove(struct fn_list* list) {
144  struct fn_node* curr = list->head;
145  struct fn_node* prev = NULL;
146  struct fn_node* next = NULL;
147
148  while (curr) {
149    next = curr->next;
150
151    if (curr->id == CURRENT_ID) {
152      if (curr == list->head) {
153        list->head = next;
154      }
155
156      if (curr == list->tail) {
157        list->tail = prev;
158      }
159
160      if (prev) {
161        prev->next = next;
162      }
163
164      free(curr);
165    } else {
166      prev = curr;
167    }
168
169    curr = next;
170  }
171}
172
173static void resize_write_buffer(uint64_t size) {
174  if (!new_file) return;
175  size += cur_pos;
176  if (size <= cur_buffer_size) return;
177  size = (size - 1) / WRITE_BUFFER_SIZE + 1;
178  size *= WRITE_BUFFER_SIZE;
179  write_buffer = realloc(write_buffer, size);
180  cur_buffer_size = size;
181}
182
183static void write_bytes(const char *s, size_t len) {
184  resize_write_buffer(len);
185  memcpy(&write_buffer[cur_pos], s, len);
186  cur_pos += len;
187}
188
189static void write_32bit_value(uint32_t i) {
190  write_bytes((char*)&i, 4);
191}
192
193static void write_64bit_value(uint64_t i) {
194  // GCOV uses a lo-/hi-word format even on big-endian systems.
195  // See also GCOVBuffer::readInt64 in LLVM.
196  uint32_t lo = (uint32_t) i;
197  uint32_t hi = (uint32_t) (i >> 32);
198  write_32bit_value(lo);
199  write_32bit_value(hi);
200}
201
202static uint32_t length_of_string(const char *s) {
203  return (strlen(s) / 4) + 1;
204}
205
206static void write_string(const char *s) {
207  uint32_t len = length_of_string(s);
208  write_32bit_value(len);
209  write_bytes(s, strlen(s));
210  write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
211}
212
213static uint32_t read_32bit_value() {
214  uint32_t val;
215
216  if (new_file)
217    return (uint32_t)-1;
218
219  val = *(uint32_t*)&write_buffer[cur_pos];
220  cur_pos += 4;
221  return val;
222}
223
224static uint32_t read_le_32bit_value() {
225  uint32_t val = 0;
226  int i;
227
228  if (new_file)
229    return (uint32_t)-1;
230
231  for (i = 0; i < 4; i++)
232    val |= write_buffer[cur_pos++] << (8*i);
233  return val;
234}
235
236static uint64_t read_64bit_value() {
237  // GCOV uses a lo-/hi-word format even on big-endian systems.
238  // See also GCOVBuffer::readInt64 in LLVM.
239  uint32_t lo = read_32bit_value();
240  uint32_t hi = read_32bit_value();
241  return ((uint64_t)hi << 32) | ((uint64_t)lo);
242}
243
244static char *mangle_filename(const char *orig_filename) {
245  char *new_filename;
246  size_t prefix_len;
247  int prefix_strip;
248  const char *prefix = lprofGetPathPrefix(&prefix_strip, &prefix_len);
249
250  if (prefix == NULL)
251    return strdup(orig_filename);
252
253  new_filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1);
254  lprofApplyPathPrefix(new_filename, orig_filename, prefix, prefix_len,
255                       prefix_strip);
256
257  return new_filename;
258}
259
260static int map_file() {
261  fseek(output_file, 0L, SEEK_END);
262  file_size = ftell(output_file);
263
264  /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an
265   * error message because it should "just work" for the user. */
266  if (file_size == 0)
267    return -1;
268
269#if defined(_WIN32)
270  HANDLE mmap_fd;
271  if (fd == -1)
272    mmap_fd = INVALID_HANDLE_VALUE;
273  else
274    mmap_fd = (HANDLE)_get_osfhandle(fd);
275
276  mmap_handle = CreateFileMapping(mmap_fd, NULL, PAGE_READWRITE, DWORD_HI(file_size), DWORD_LO(file_size), NULL);
277  if (mmap_handle == NULL) {
278    fprintf(stderr, "profiling: %s: cannot create file mapping: %lu\n",
279            filename, GetLastError());
280    return -1;
281  }
282
283  write_buffer = MapViewOfFile(mmap_handle, FILE_MAP_WRITE, 0, 0, file_size);
284  if (write_buffer == NULL) {
285    fprintf(stderr, "profiling: %s: cannot map: %lu\n", filename,
286            GetLastError());
287    CloseHandle(mmap_handle);
288    return -1;
289  }
290#else
291  write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
292                      MAP_FILE | MAP_SHARED, fd, 0);
293  if (write_buffer == (void *)-1) {
294    int errnum = errno;
295    fprintf(stderr, "profiling: %s: cannot map: %s\n", filename,
296            strerror(errnum));
297    return -1;
298  }
299#endif
300
301  return 0;
302}
303
304static void unmap_file() {
305#if defined(_WIN32)
306  if (!FlushViewOfFile(write_buffer, file_size)) {
307    fprintf(stderr, "profiling: %s: cannot flush mapped view: %lu\n", filename,
308            GetLastError());
309  }
310
311  if (!UnmapViewOfFile(write_buffer)) {
312    fprintf(stderr, "profiling: %s: cannot unmap mapped view: %lu\n", filename,
313            GetLastError());
314  }
315
316  if (!CloseHandle(mmap_handle)) {
317    fprintf(stderr, "profiling: %s: cannot close file mapping handle: %lu\n",
318            filename, GetLastError());
319  }
320
321  mmap_handle = NULL;
322#else
323  if (msync(write_buffer, file_size, MS_SYNC) == -1) {
324    int errnum = errno;
325    fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
326            strerror(errnum));
327  }
328
329  /* We explicitly ignore errors from unmapping because at this point the data
330   * is written and we don't care.
331   */
332  (void)munmap(write_buffer, file_size);
333#endif
334
335  write_buffer = NULL;
336  file_size = 0;
337}
338
339/*
340 * --- LLVM line counter API ---
341 */
342
343/* A file in this case is a translation unit. Each .o file built with line
344 * profiling enabled will emit to a different file. Only one file may be
345 * started at a time.
346 */
347COMPILER_RT_VISIBILITY
348void llvm_gcda_start_file(const char *orig_filename, const char version[4],
349                          uint32_t checksum) {
350  const char *mode = "r+b";
351  filename = mangle_filename(orig_filename);
352
353  /* Try just opening the file. */
354  new_file = 0;
355  fd = open(filename, O_RDWR | O_BINARY);
356
357  if (fd == -1) {
358    /* Try opening the file, creating it if necessary. */
359    new_file = 1;
360    mode = "w+b";
361    fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
362    if (fd == -1) {
363      /* Try creating the directories first then opening the file. */
364      __llvm_profile_recursive_mkdir(filename);
365      fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
366      if (fd == -1) {
367        /* Bah! It's hopeless. */
368        int errnum = errno;
369        fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
370                strerror(errnum));
371        return;
372      }
373    }
374  }
375
376  /* Try to flock the file to serialize concurrent processes writing out to the
377   * same GCDA. This can fail if the filesystem doesn't support it, but in that
378   * case we'll just carry on with the old racy behaviour and hope for the best.
379   */
380  lprofLockFd(fd);
381  output_file = fdopen(fd, mode);
382
383  /* Initialize the write buffer. */
384  write_buffer = NULL;
385  cur_buffer_size = 0;
386  cur_pos = 0;
387
388  if (new_file) {
389    resize_write_buffer(WRITE_BUFFER_SIZE);
390    memset(write_buffer, 0, WRITE_BUFFER_SIZE);
391  } else {
392    if (map_file() == -1) {
393      /* mmap failed, try to recover by clobbering */
394      new_file = 1;
395      write_buffer = NULL;
396      cur_buffer_size = 0;
397      resize_write_buffer(WRITE_BUFFER_SIZE);
398      memset(write_buffer, 0, WRITE_BUFFER_SIZE);
399    }
400  }
401
402  /* gcda file, version, stamp checksum. */
403  write_bytes("adcg", 4);
404  write_bytes(version, 4);
405  write_32bit_value(checksum);
406
407#ifdef DEBUG_GCDAPROFILING
408  fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
409#endif
410}
411
412/* Given an array of pointers to counters (counters), increment the n-th one,
413 * where we're also given a pointer to n (predecessor).
414 */
415COMPILER_RT_VISIBILITY
416void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
417                                          uint64_t **counters) {
418  uint64_t *counter;
419  uint32_t pred;
420
421  pred = *predecessor;
422  if (pred == 0xffffffff)
423    return;
424  counter = counters[pred];
425
426  /* Don't crash if the pred# is out of sync. This can happen due to threads,
427     or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
428  if (counter)
429    ++*counter;
430#ifdef DEBUG_GCDAPROFILING
431  else
432    fprintf(stderr,
433            "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n",
434            *counter, *predecessor);
435#endif
436}
437
438COMPILER_RT_VISIBILITY
439void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
440                             uint32_t func_checksum, uint8_t use_extra_checksum,
441                             uint32_t cfg_checksum) {
442  uint32_t len = 2;
443
444  if (use_extra_checksum)
445    len++;
446#ifdef DEBUG_GCDAPROFILING
447  fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident,
448          function_name ? function_name : "NULL");
449#endif
450  if (!output_file) return;
451
452  /* function tag */
453  write_bytes("\0\0\0\1", 4);
454  if (function_name)
455    len += 1 + length_of_string(function_name);
456  write_32bit_value(len);
457  write_32bit_value(ident);
458  write_32bit_value(func_checksum);
459  if (use_extra_checksum)
460    write_32bit_value(cfg_checksum);
461  if (function_name)
462    write_string(function_name);
463}
464
465COMPILER_RT_VISIBILITY
466void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
467  uint32_t i;
468  uint64_t *old_ctrs = NULL;
469  uint32_t val = 0;
470  uint64_t save_cur_pos = cur_pos;
471
472  if (!output_file) return;
473
474  val = read_le_32bit_value();
475
476  if (val != (uint32_t)-1) {
477    /* There are counters present in the file. Merge them. */
478    if (val != 0x01a10000) {
479      fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
480                      "corrupt arc tag (0x%08x)\n",
481              filename, val);
482      return;
483    }
484
485    val = read_32bit_value();
486    if (val == (uint32_t)-1 || val / 2 != num_counters) {
487      fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
488                      "mismatched number of counters (%d)\n",
489              filename, val);
490      return;
491    }
492
493    old_ctrs = malloc(sizeof(uint64_t) * num_counters);
494    for (i = 0; i < num_counters; ++i)
495      old_ctrs[i] = read_64bit_value();
496  }
497
498  cur_pos = save_cur_pos;
499
500  /* Counter #1 (arcs) tag */
501  write_bytes("\0\0\xa1\1", 4);
502  write_32bit_value(num_counters * 2);
503  for (i = 0; i < num_counters; ++i) {
504    counters[i] += (old_ctrs ? old_ctrs[i] : 0);
505    write_64bit_value(counters[i]);
506  }
507
508  free(old_ctrs);
509
510#ifdef DEBUG_GCDAPROFILING
511  fprintf(stderr, "llvmgcda:   %u arcs\n", num_counters);
512  for (i = 0; i < num_counters; ++i)
513    fprintf(stderr, "llvmgcda:   %llu\n", (unsigned long long)counters[i]);
514#endif
515}
516
517COMPILER_RT_VISIBILITY
518void llvm_gcda_summary_info() {
519  const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
520  uint32_t i;
521  uint32_t runs = 1;
522  static uint32_t run_counted = 0; // We only want to increase the run count once.
523  uint32_t val = 0;
524  uint64_t save_cur_pos = cur_pos;
525
526  if (!output_file) return;
527
528  val = read_le_32bit_value();
529
530  if (val != (uint32_t)-1) {
531    /* There are counters present in the file. Merge them. */
532    if (val != 0xa1000000) {
533      fprintf(stderr, "profiling: %s: cannot merge previous run count: "
534                      "corrupt object tag (0x%08x)\n",
535              filename, val);
536      return;
537    }
538
539    val = read_32bit_value(); /* length */
540    if (val != obj_summary_len) {
541      fprintf(stderr, "profiling: %s: cannot merge previous run count: "
542                      "mismatched object length (%d)\n",
543              filename, val);
544      return;
545    }
546
547    read_32bit_value(); /* checksum, unused */
548    read_32bit_value(); /* num, unused */
549    uint32_t prev_runs = read_32bit_value();
550    /* Add previous run count to new counter, if not already counted before. */
551    runs = run_counted ? prev_runs : prev_runs + 1;
552  }
553
554  cur_pos = save_cur_pos;
555
556  /* Object summary tag */
557  write_bytes("\0\0\0\xa1", 4);
558  write_32bit_value(obj_summary_len);
559  write_32bit_value(0); /* checksum, unused */
560  write_32bit_value(0); /* num, unused */
561  write_32bit_value(runs);
562  for (i = 3; i < obj_summary_len; ++i)
563    write_32bit_value(0);
564
565  /* Program summary tag */
566  write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
567  write_32bit_value(0); /* 0 length */
568
569  run_counted = 1;
570
571#ifdef DEBUG_GCDAPROFILING
572  fprintf(stderr, "llvmgcda:   %u runs\n", runs);
573#endif
574}
575
576COMPILER_RT_VISIBILITY
577void llvm_gcda_end_file() {
578  /* Write out EOF record. */
579  if (output_file) {
580    write_bytes("\0\0\0\0\0\0\0\0", 8);
581
582    if (new_file) {
583      fwrite(write_buffer, cur_pos, 1, output_file);
584      free(write_buffer);
585    } else {
586      unmap_file();
587    }
588
589    fflush(output_file);
590    lprofUnlockFd(fd);
591    fclose(output_file);
592    output_file = NULL;
593    write_buffer = NULL;
594  }
595  free(filename);
596
597#ifdef DEBUG_GCDAPROFILING
598  fprintf(stderr, "llvmgcda: -----\n");
599#endif
600}
601
602COMPILER_RT_VISIBILITY
603void llvm_register_writeout_function(fn_ptr fn) {
604  fn_list_insert(&writeout_fn_list, fn);
605}
606
607COMPILER_RT_VISIBILITY
608void llvm_writeout_files(void) {
609  struct fn_node *curr = writeout_fn_list.head;
610
611  while (curr) {
612    if (curr->id == CURRENT_ID) {
613      curr->fn();
614    }
615    curr = curr->next;
616  }
617}
618
619COMPILER_RT_VISIBILITY
620void llvm_delete_writeout_function_list(void) {
621  fn_list_remove(&writeout_fn_list);
622}
623
624COMPILER_RT_VISIBILITY
625void llvm_register_flush_function(fn_ptr fn) {
626  fn_list_insert(&flush_fn_list, fn);
627}
628
629void __gcov_flush() {
630  struct fn_node* curr = flush_fn_list.head;
631
632  while (curr) {
633    curr->fn();
634    curr = curr->next;
635  }
636}
637
638COMPILER_RT_VISIBILITY
639void llvm_delete_flush_function_list(void) {
640  fn_list_remove(&flush_fn_list);
641}
642
643COMPILER_RT_VISIBILITY
644void llvm_register_reset_function(fn_ptr fn) {
645  fn_list_insert(&reset_fn_list, fn);
646}
647
648COMPILER_RT_VISIBILITY
649void llvm_delete_reset_function_list(void) { fn_list_remove(&reset_fn_list); }
650
651COMPILER_RT_VISIBILITY
652void llvm_reset_counters(void) {
653  struct fn_node *curr = reset_fn_list.head;
654
655  while (curr) {
656    if (curr->id == CURRENT_ID) {
657      curr->fn();
658    }
659    curr = curr->next;
660  }
661}
662
663#if !defined(_WIN32)
664COMPILER_RT_VISIBILITY
665pid_t __gcov_fork() {
666  pid_t parent_pid = getpid();
667  pid_t pid = fork();
668
669  if (pid == 0) {
670    pid_t child_pid = getpid();
671    if (child_pid != parent_pid) {
672      // The pid changed so we've a fork (one could have its own fork function)
673      // Just reset the counters for this child process
674      // threads.
675      llvm_reset_counters();
676    }
677  }
678  return pid;
679}
680#endif
681
682COMPILER_RT_VISIBILITY
683void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn, fn_ptr rfn) {
684  static int atexit_ran = 0;
685
686  if (wfn)
687    llvm_register_writeout_function(wfn);
688
689  if (ffn)
690    llvm_register_flush_function(ffn);
691
692  if (rfn)
693    llvm_register_reset_function(rfn);
694
695  if (atexit_ran == 0) {
696    atexit_ran = 1;
697
698    /* Make sure we write out the data and delete the data structures. */
699    atexit(llvm_delete_reset_function_list);
700    atexit(llvm_delete_flush_function_list);
701    atexit(llvm_delete_writeout_function_list);
702    atexit(llvm_writeout_files);
703  }
704}
705
706#endif
707