1b1928704201034c785a26296a49f69355eb56a05Nick Lewycky/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
2b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
3b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*                     The LLVM Compiler Infrastructure
4b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
5b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* This file is distributed under the University of Illinois Open Source
6b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* License. See LICENSE.TXT for details.
7b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
8b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*===----------------------------------------------------------------------===*|
9b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
10b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* This file implements the call back routines for the gcov profiling
11b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* instrumentation pass. Link against this library when running code through
12b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* the -insert-gcov-profiling LLVM pass.
13b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
14b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* We emit files in a corrupt version of GCOV's "gcda" file format. These files
15b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* are only close enough that LCOV will happily parse them. Anything that lcov
16b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|* ignores is missing.
17b1928704201034c785a26296a49f69355eb56a05Nick Lewycky|*
181790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky|* TODO: gcov is multi-process safe by having each exit open the existing file
191790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky|* and append to it. We'd like to achieve that and be thread-safe too.
201790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky|*
21b1928704201034c785a26296a49f69355eb56a05Nick Lewycky\*===----------------------------------------------------------------------===*/
22b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
23b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include "llvm/Support/DataTypes.h"
24b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include <stdio.h>
25b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include <stdlib.h>
26b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include <string.h>
275e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky#include <sys/stat.h>
285e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky#include <sys/types.h>
2970b582ab9c6d69ff1ba14c90c016da61477fc9dcBenjamin Kramer#ifdef _WIN32
3097938081f321bc08ded74fc452523c35b7f9f17eFrancois Pichet#include <direct.h>
3197938081f321bc08ded74fc452523c35b7f9f17eFrancois Pichet#endif
32b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
33ece78a30bdd4c26edcd5304aca1415ebc8b27756Nick Lewycky/* #define DEBUG_GCDAPROFILING */
34b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
35b1928704201034c785a26296a49f69355eb56a05Nick Lewycky/*
36b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * --- GCOV file format I/O primitives ---
37b1928704201034c785a26296a49f69355eb56a05Nick Lewycky */
38b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
39b1928704201034c785a26296a49f69355eb56a05Nick Lewyckystatic FILE *output_file = NULL;
40b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
41b1928704201034c785a26296a49f69355eb56a05Nick Lewyckystatic void write_int32(uint32_t i) {
42b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fwrite(&i, 4, 1, output_file);
43b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
44b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
45b1928704201034c785a26296a49f69355eb56a05Nick Lewyckystatic void write_int64(uint64_t i) {
46b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  uint32_t lo, hi;
47571c0e95fa74c570f1c42f15b63ba8c68cba86b1Benjamin Kramer  lo = i >>  0;
48571c0e95fa74c570f1c42f15b63ba8c68cba86b1Benjamin Kramer  hi = i >> 32;
49b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
50b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  write_int32(lo);
51b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  write_int32(hi);
52b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
53b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
545409a188328d9de3755febc23558d4fc1797d04eNick Lewyckystatic uint32_t length_of_string(const char *s) {
55d363ff334d796c7f3df834d928a10d88ed758454Nick Lewycky  return (strlen(s) / 4) + 1;
565409a188328d9de3755febc23558d4fc1797d04eNick Lewycky}
575409a188328d9de3755febc23558d4fc1797d04eNick Lewycky
585409a188328d9de3755febc23558d4fc1797d04eNick Lewyckystatic void write_string(const char *s) {
595409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  uint32_t len = length_of_string(s);
605409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  write_int32(len);
615409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  fwrite(s, strlen(s), 1, output_file);
625409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);
635409a188328d9de3755febc23558d4fc1797d04eNick Lewycky}
645409a188328d9de3755febc23558d4fc1797d04eNick Lewycky
657a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewyckystatic char *mangle_filename(const char *orig_filename) {
667a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  /* TODO: handle GCOV_PREFIX_STRIP */
677a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  const char *prefix;
687a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  char *filename = 0;
697a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
707a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  prefix = getenv("GCOV_PREFIX");
717a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
727a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  if (!prefix)
73d006ddc195934cf896d2f5e512d38e196923c79bNick Lewycky    return strdup(orig_filename);
747a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
757a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1);
767a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  strcpy(filename, prefix);
777a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  strcat(filename, "/");
787a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  strcat(filename, orig_filename);
797a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
807a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  return filename;
817a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky}
827a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
835e436b3b0ef06258ed2d7929946eb00684973183Nick Lewyckystatic void recursive_mkdir(const char *filename) {
845e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky  char *pathname;
855e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky  int i, e;
865e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky
875e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky  for (i = 1, e = strlen(filename); i != e; ++i) {
885e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky    if (filename[i] == '/') {
895e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky      pathname = malloc(i + 1);
905e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky      strncpy(pathname, filename, i);
915e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky      pathname[i] = '\0';
92aeebc35886726c8d378033d7122f29feba5d4134Eli Friedman#ifdef _WIN32
9397938081f321bc08ded74fc452523c35b7f9f17eFrancois Pichet      _mkdir(pathname);
9497938081f321bc08ded74fc452523c35b7f9f17eFrancois Pichet#else
955e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky      mkdir(pathname, 0750);  /* some of these will fail, ignore it. */
9697938081f321bc08ded74fc452523c35b7f9f17eFrancois Pichet#endif
975e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky      free(pathname);
985e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky    }
995e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky  }
1005e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky}
1015e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky
102b1928704201034c785a26296a49f69355eb56a05Nick Lewycky/*
103b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * --- LLVM line counter API ---
104b1928704201034c785a26296a49f69355eb56a05Nick Lewycky */
105b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
106b1928704201034c785a26296a49f69355eb56a05Nick Lewycky/* A file in this case is a translation unit. Each .o file built with line
107b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * profiling enabled will emit to a different file. Only one file may be
108b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * started at a time.
109b1928704201034c785a26296a49f69355eb56a05Nick Lewycky */
1107a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewyckyvoid llvm_gcda_start_file(const char *orig_filename) {
1117a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  char *filename;
1127a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  filename = mangle_filename(orig_filename);
1135e436b3b0ef06258ed2d7929946eb00684973183Nick Lewycky  recursive_mkdir(filename);
1147a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  output_file = fopen(filename, "wb");
115b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
11666e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling  if (!output_file) {
1177242a4fb86d9b369a467e3a85ce02bc94c6d9dc8Bill Wendling    const char *cptr = strrchr(orig_filename, '/');
1187242a4fb86d9b369a467e3a85ce02bc94c6d9dc8Bill Wendling    output_file = fopen(cptr ? cptr + 1 : orig_filename, "wb");
11966e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling
12066e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling    if (!output_file) {
12166e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling      fprintf(stderr, "LLVM profiling runtime: while opening '%s': ",
122d4ec0547a210f9f2f34e0c4631586a179bd97571Bill Wendling              cptr ? cptr + 1 : orig_filename);
12366e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling      perror("");
12466e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling      exit(1);
12566e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling    }
12666e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling  }
12766e30f8db180bdc0fba637c84e7b72396a08d8f2Bill Wendling
128b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  /* gcda file, version 404*, stamp LLVM. */
129ad759c5a073dbd66d3297347c64da3ab148a92a4Bill Wendling#ifdef __APPLE__
130ad759c5a073dbd66d3297347c64da3ab148a92a4Bill Wendling  fwrite("adcg*204MVLL", 12, 1, output_file);
131ad759c5a073dbd66d3297347c64da3ab148a92a4Bill Wendling#else
132b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fwrite("adcg*404MVLL", 12, 1, output_file);
133ad759c5a073dbd66d3297347c64da3ab148a92a4Bill Wendling#endif
134b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
135b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef DEBUG_GCDAPROFILING
1367a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  printf("llvmgcda: [%s]\n", orig_filename);
1371790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky#endif
1387a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
1397a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  free(filename);
1401790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky}
1411790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
1421790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky/* Given an array of pointers to counters (counters), increment the n-th one,
1431790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * where we're also given a pointer to n (predecessor).
1441790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky */
1451790c9cbb6714e81eab1412909a2320acaecc43bNick Lewyckyvoid llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
1461790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                                          uint64_t **counters) {
1471790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  uint64_t *counter;
1487a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  uint32_t pred;
1497a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky
1507a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  pred = *predecessor;
1517a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  if (pred == 0xffffffff)
1521790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    return;
1537a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  counter = counters[pred];
1541790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
1551790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  /* Don't crash if the pred# is out of sync. This can happen due to threads,
1561790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky     or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
1577a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky  if (counter)
1581790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    ++*counter;
1591790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky#ifdef DEBUG_GCDAPROFILING
1601790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  else
1611790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n",
1621790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky           state_table_row, *predecessor);
163b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
164b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
165b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
1665409a188328d9de3755febc23558d4fc1797d04eNick Lewyckyvoid llvm_gcda_emit_function(uint32_t ident, const char *function_name) {
167b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef DEBUG_GCDAPROFILING
1681790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  printf("llvmgcda: function id=%x\n", ident);
169b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
170b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
171b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  /* function tag */
172b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fwrite("\0\0\0\1", 4, 1, output_file);
1735409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  write_int32(3 + 1 + length_of_string(function_name));
174b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  write_int32(ident);
175b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  write_int32(0);
1765409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  write_int32(0);
1775409a188328d9de3755febc23558d4fc1797d04eNick Lewycky  write_string(function_name);
178b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
179b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
180b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyvoid llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
181b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  uint32_t i;
182b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  /* counter #1 (arcs) tag */
183b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fwrite("\0\0\xa1\1", 4, 1, output_file);
184b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  write_int32(num_counters * 2);
185b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  for (i = 0; i < num_counters; ++i) {
186b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    write_int64(counters[i]);
187b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  }
188b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
189b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef DEBUG_GCDAPROFILING
1901790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  printf("llvmgcda:   %u arcs\n", num_counters);
191b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  for (i = 0; i < num_counters; ++i) {
1921790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    printf("llvmgcda:   %llu\n", (unsigned long long)counters[i]);
193b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  }
194b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
195b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
196b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
197b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyvoid llvm_gcda_end_file() {
198b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  /* Write out EOF record. */
199b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);
200b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  fclose(output_file);
201b1928704201034c785a26296a49f69355eb56a05Nick Lewycky  output_file = NULL;
202b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
203b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef DEBUG_GCDAPROFILING
2041790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky  printf("llvmgcda: -----\n");
205b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
206b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
207