Fix register printing in disassembling of push/pop of segment registers and in/out...
[oota-llvm.git] / runtime / libprofile / GCDAProfiling.c
index d5fcd17529bde0e95ee5b3d4936401ab6aa35b45..ac3a62c79f4bbc7a1e60e5697e72cbc53a59310f 100644 (file)
 |* are only close enough that LCOV will happily parse them. Anything that lcov
 |* ignores is missing.
 |*
+|* TODO: gcov is multi-process safe by having each exit open the existing file
+|* and append to it. We'd like to achieve that and be thread-safe too.
+|*
 \*===----------------------------------------------------------------------===*/
 
 #include "llvm/Support/DataTypes.h"
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef _MSC_VER
+#include <direct.h>
+#endif
 
 /* #define DEBUG_GCDAPROFILING */
 
@@ -37,13 +44,61 @@ static void write_int32(uint32_t i) {
 
 static void write_int64(uint64_t i) {
   uint32_t lo, hi;
-  lo = i & 0x00000000ffffffff;
-  hi = i & 0xffffffff00000000;
+  lo = i >>  0;
+  hi = i >> 32;
 
   write_int32(lo);
   write_int32(hi);
 }
 
+static uint32_t length_of_string(const char *s) {
+  return (strlen(s) / 4) + 1;
+}
+
+static void write_string(const char *s) {
+  uint32_t len = length_of_string(s);
+  write_int32(len);
+  fwrite(s, strlen(s), 1, output_file);
+  fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);
+}
+
+static char *mangle_filename(const char *orig_filename) {
+  /* TODO: handle GCOV_PREFIX_STRIP */
+  const char *prefix;
+  char *filename = 0;
+
+  prefix = getenv("GCOV_PREFIX");
+
+  if (!prefix)
+    return strdup(orig_filename);
+
+  filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1);
+  strcpy(filename, prefix);
+  strcat(filename, "/");
+  strcat(filename, orig_filename);
+
+  return filename;
+}
+
+static void recursive_mkdir(const char *filename) {
+  char *pathname;
+  int i, e;
+
+  for (i = 1, e = strlen(filename); i != e; ++i) {
+    if (filename[i] == '/') {
+      pathname = malloc(i + 1);
+      strncpy(pathname, filename, i);
+      pathname[i] = '\0';
+#ifdef _WIN32
+      _mkdir(pathname);
+#else
+      mkdir(pathname, 0750);  /* some of these will fail, ignore it. */
+#endif
+      free(pathname);
+    }
+  }
+}
+
 /*
  * --- LLVM line counter API ---
  */
@@ -52,27 +107,62 @@ static void write_int64(uint64_t i) {
  * profiling enabled will emit to a different file. Only one file may be
  * started at a time.
  */
-void llvm_gcda_start_file(const char *filename) {
-  output_file = fopen(filename, "w+");
+void llvm_gcda_start_file(const char *orig_filename) {
+  char *filename;
+  filename = mangle_filename(orig_filename);
+  recursive_mkdir(filename);
+  output_file = fopen(filename, "wb");
 
   /* gcda file, version 404*, stamp LLVM. */
+#ifdef __APPLE__
+  fwrite("adcg*204MVLL", 12, 1, output_file);
+#else
   fwrite("adcg*404MVLL", 12, 1, output_file);
+#endif
+
+#ifdef DEBUG_GCDAPROFILING
+  printf("llvmgcda: [%s]\n", orig_filename);
+#endif
+
+  free(filename);
+}
 
+/* Given an array of pointers to counters (counters), increment the n-th one,
+ * where we're also given a pointer to n (predecessor).
+ */
+void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
+                                          uint64_t **counters) {
+  uint64_t *counter;
+  uint32_t pred;
+
+  pred = *predecessor;
+  if (pred == 0xffffffff)
+    return;
+  counter = counters[pred];
+
+  /* Don't crash if the pred# is out of sync. This can happen due to threads,
+     or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
+  if (counter)
+    ++*counter;
 #ifdef DEBUG_GCDAPROFILING
-  printf("[%s]\n", filename);
+  else
+    printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n",
+           state_table_row, *predecessor);
 #endif
 }
 
-void llvm_gcda_emit_function(uint32_t ident) {
+void llvm_gcda_emit_function(uint32_t ident, const char *function_name) {
 #ifdef DEBUG_GCDAPROFILING
-  printf("function id=%x\n", ident);
+  printf("llvmgcda: function id=%x\n", ident);
 #endif
 
   /* function tag */  
   fwrite("\0\0\0\1", 4, 1, output_file);
-  write_int32(2);
+  write_int32(3 + 1 + length_of_string(function_name));
   write_int32(ident);
   write_int32(0);
+  write_int32(0);
+  write_string(function_name);
 }
 
 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
@@ -85,9 +175,9 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
   }
 
 #ifdef DEBUG_GCDAPROFILING
-  printf("  %u arcs\n", num_counters);
+  printf("llvmgcda:   %u arcs\n", num_counters);
   for (i = 0; i < num_counters; ++i) {
-    printf("  %llu\n", (unsigned long long)counters[i]);
+    printf("llvmgcda:   %llu\n", (unsigned long long)counters[i]);
   }
 #endif
 }
@@ -99,6 +189,6 @@ void llvm_gcda_end_file() {
   output_file = NULL;
 
 #ifdef DEBUG_GCDAPROFILING
-  printf("-----\n");
+  printf("llvmgcda: -----\n");
 #endif
 }