blob: ee48ab5b6b097d228a40c8633aa4ce3128fda5e1 [file] [log] [blame]
Nick Lewyckyb1928702011-04-16 01:20:23 +00001/*===- 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\*===----------------------------------------------------------------------===*/
19
20#include "llvm/Support/DataTypes.h"
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26// #define DEBUG_GCDAPROFILING
27
28/*
29 * --- GCOV file format I/O primitives ---
30 */
31
32static FILE *output_file = NULL;
33
34static void write_int32(uint32_t i) {
35 fwrite(&i, 4, 1, output_file);
36}
37
38static void write_int64(uint64_t i) {
39 uint32_t lo, hi;
40 lo = i & 0x00000000ffffffff;
41 hi = i & 0xffffffff00000000;
42
43 write_int32(lo);
44 write_int32(hi);
45}
46
47/*
48 * --- LLVM line counter API ---
49 */
50
51/* A file in this case is a translation unit. Each .o file built with line
52 * profiling enabled will emit to a different file. Only one file may be
53 * started at a time.
54 */
55void llvm_gcda_start_file(const char *filename) {
56 output_file = fopen(filename, "w+");
57
58 /* gcda file, version 404*, stamp LLVM. */
59 fwrite("adcg*404MVLL", 12, 1, output_file);
60
61#ifdef DEBUG_GCDAPROFILING
62 printf("[%s]\n", filename);
63#endif
64}
65
66void llvm_gcda_emit_function(uint32_t ident) {
67#ifdef DEBUG_GCDAPROFILING
68 printf("function id=%x\n", ident);
69#endif
70
71 /* function tag */
72 fwrite("\0\0\0\1", 4, 1, output_file);
73 write_int32(2);
74 write_int32(ident);
75 write_int32(0);
76}
77
78void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
79 uint32_t i;
80 /* counter #1 (arcs) tag */
81 fwrite("\0\0\xa1\1", 4, 1, output_file);
82 write_int32(num_counters * 2);
83 for (i = 0; i < num_counters; ++i) {
84 write_int64(counters[i]);
85 }
86
87#ifdef DEBUG_GCDAPROFILING
88 printf(" %u arcs\n", num_counters);
89 for (i = 0; i < num_counters; ++i) {
90 printf(" %llu\n", (unsigned long long)counters[i]);
91 }
92#endif
93}
94
95void llvm_gcda_end_file() {
96 /* Write out EOF record. */
97 fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);
98 fclose(output_file);
99 output_file = NULL;
100
101#ifdef DEBUG_GCDAPROFILING
102 printf("-----\n");
103#endif
104}