1*0a6a1f1dSLionel Sambuc /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
2*0a6a1f1dSLionel Sambuc |*
3*0a6a1f1dSLionel Sambuc |* The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc |*
5*0a6a1f1dSLionel Sambuc |* This file is distributed under the University of Illinois Open Source
6*0a6a1f1dSLionel Sambuc |* License. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc |*
8*0a6a1f1dSLionel Sambuc \*===----------------------------------------------------------------------===*/
9*0a6a1f1dSLionel Sambuc
10*0a6a1f1dSLionel Sambuc #include "InstrProfiling.h"
11*0a6a1f1dSLionel Sambuc #include <stdio.h>
12*0a6a1f1dSLionel Sambuc #include <stdlib.h>
13*0a6a1f1dSLionel Sambuc #include <string.h>
14*0a6a1f1dSLionel Sambuc
15*0a6a1f1dSLionel Sambuc #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
16*0a6a1f1dSLionel Sambuc
writeFile(FILE * File)17*0a6a1f1dSLionel Sambuc static int writeFile(FILE *File) {
18*0a6a1f1dSLionel Sambuc /* Match logic in __llvm_profile_write_buffer(). */
19*0a6a1f1dSLionel Sambuc const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
20*0a6a1f1dSLionel Sambuc const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
21*0a6a1f1dSLionel Sambuc const uint64_t *CountersBegin = __llvm_profile_counters_begin();
22*0a6a1f1dSLionel Sambuc const uint64_t *CountersEnd = __llvm_profile_counters_end();
23*0a6a1f1dSLionel Sambuc const char *NamesBegin = __llvm_profile_names_begin();
24*0a6a1f1dSLionel Sambuc const char *NamesEnd = __llvm_profile_names_end();
25*0a6a1f1dSLionel Sambuc
26*0a6a1f1dSLionel Sambuc /* Calculate size of sections. */
27*0a6a1f1dSLionel Sambuc const uint64_t DataSize = DataEnd - DataBegin;
28*0a6a1f1dSLionel Sambuc const uint64_t CountersSize = CountersEnd - CountersBegin;
29*0a6a1f1dSLionel Sambuc const uint64_t NamesSize = NamesEnd - NamesBegin;
30*0a6a1f1dSLionel Sambuc const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
31*0a6a1f1dSLionel Sambuc
32*0a6a1f1dSLionel Sambuc /* Enough zeroes for padding. */
33*0a6a1f1dSLionel Sambuc const char Zeroes[sizeof(uint64_t)] = {0};
34*0a6a1f1dSLionel Sambuc
35*0a6a1f1dSLionel Sambuc /* Create the header. */
36*0a6a1f1dSLionel Sambuc uint64_t Header[PROFILE_HEADER_SIZE];
37*0a6a1f1dSLionel Sambuc Header[0] = __llvm_profile_get_magic();
38*0a6a1f1dSLionel Sambuc Header[1] = __llvm_profile_get_version();
39*0a6a1f1dSLionel Sambuc Header[2] = DataSize;
40*0a6a1f1dSLionel Sambuc Header[3] = CountersSize;
41*0a6a1f1dSLionel Sambuc Header[4] = NamesSize;
42*0a6a1f1dSLionel Sambuc Header[5] = (uintptr_t)CountersBegin;
43*0a6a1f1dSLionel Sambuc Header[6] = (uintptr_t)NamesBegin;
44*0a6a1f1dSLionel Sambuc
45*0a6a1f1dSLionel Sambuc /* Write the data. */
46*0a6a1f1dSLionel Sambuc #define CHECK_fwrite(Data, Size, Length, File) \
47*0a6a1f1dSLionel Sambuc do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
48*0a6a1f1dSLionel Sambuc CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
49*0a6a1f1dSLionel Sambuc CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
50*0a6a1f1dSLionel Sambuc CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
51*0a6a1f1dSLionel Sambuc CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
52*0a6a1f1dSLionel Sambuc CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
53*0a6a1f1dSLionel Sambuc #undef CHECK_fwrite
54*0a6a1f1dSLionel Sambuc
55*0a6a1f1dSLionel Sambuc return 0;
56*0a6a1f1dSLionel Sambuc }
57*0a6a1f1dSLionel Sambuc
writeFileWithName(const char * OutputName)58*0a6a1f1dSLionel Sambuc static int writeFileWithName(const char *OutputName) {
59*0a6a1f1dSLionel Sambuc int RetVal;
60*0a6a1f1dSLionel Sambuc FILE *OutputFile;
61*0a6a1f1dSLionel Sambuc if (!OutputName || !OutputName[0])
62*0a6a1f1dSLionel Sambuc return -1;
63*0a6a1f1dSLionel Sambuc
64*0a6a1f1dSLionel Sambuc /* Append to the file to support profiling multiple shared objects. */
65*0a6a1f1dSLionel Sambuc OutputFile = fopen(OutputName, "a");
66*0a6a1f1dSLionel Sambuc if (!OutputFile)
67*0a6a1f1dSLionel Sambuc return -1;
68*0a6a1f1dSLionel Sambuc
69*0a6a1f1dSLionel Sambuc RetVal = writeFile(OutputFile);
70*0a6a1f1dSLionel Sambuc
71*0a6a1f1dSLionel Sambuc fclose(OutputFile);
72*0a6a1f1dSLionel Sambuc return RetVal;
73*0a6a1f1dSLionel Sambuc }
74*0a6a1f1dSLionel Sambuc
75*0a6a1f1dSLionel Sambuc __attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
76*0a6a1f1dSLionel Sambuc __attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
77*0a6a1f1dSLionel Sambuc
setFilename(const char * Filename,int OwnsFilename)78*0a6a1f1dSLionel Sambuc static void setFilename(const char *Filename, int OwnsFilename) {
79*0a6a1f1dSLionel Sambuc if (__llvm_profile_OwnsFilename)
80*0a6a1f1dSLionel Sambuc free(UNCONST(__llvm_profile_CurrentFilename));
81*0a6a1f1dSLionel Sambuc
82*0a6a1f1dSLionel Sambuc __llvm_profile_CurrentFilename = Filename;
83*0a6a1f1dSLionel Sambuc __llvm_profile_OwnsFilename = OwnsFilename;
84*0a6a1f1dSLionel Sambuc }
85*0a6a1f1dSLionel Sambuc
truncateCurrentFile(void)86*0a6a1f1dSLionel Sambuc static void truncateCurrentFile(void) {
87*0a6a1f1dSLionel Sambuc const char *Filename = __llvm_profile_CurrentFilename;
88*0a6a1f1dSLionel Sambuc if (!Filename || !Filename[0])
89*0a6a1f1dSLionel Sambuc return;
90*0a6a1f1dSLionel Sambuc
91*0a6a1f1dSLionel Sambuc /* Truncate the file. Later we'll reopen and append. */
92*0a6a1f1dSLionel Sambuc FILE *File = fopen(Filename, "w");
93*0a6a1f1dSLionel Sambuc if (!File)
94*0a6a1f1dSLionel Sambuc return;
95*0a6a1f1dSLionel Sambuc fclose(File);
96*0a6a1f1dSLionel Sambuc }
97*0a6a1f1dSLionel Sambuc
setDefaultFilename(void)98*0a6a1f1dSLionel Sambuc static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
99*0a6a1f1dSLionel Sambuc
100*0a6a1f1dSLionel Sambuc int getpid(void);
setFilenameFromEnvironment(void)101*0a6a1f1dSLionel Sambuc static int setFilenameFromEnvironment(void) {
102*0a6a1f1dSLionel Sambuc const char *Filename = getenv("LLVM_PROFILE_FILE");
103*0a6a1f1dSLionel Sambuc if (!Filename || !Filename[0])
104*0a6a1f1dSLionel Sambuc return -1;
105*0a6a1f1dSLionel Sambuc
106*0a6a1f1dSLionel Sambuc /* Check the filename for "%p", which indicates a pid-substitution. */
107*0a6a1f1dSLionel Sambuc #define MAX_PID_SIZE 16
108*0a6a1f1dSLionel Sambuc char PidChars[MAX_PID_SIZE] = {0};
109*0a6a1f1dSLionel Sambuc int NumPids = 0;
110*0a6a1f1dSLionel Sambuc int PidLength = 0;
111*0a6a1f1dSLionel Sambuc int I;
112*0a6a1f1dSLionel Sambuc for (I = 0; Filename[I]; ++I)
113*0a6a1f1dSLionel Sambuc if (Filename[I] == '%' && Filename[++I] == 'p')
114*0a6a1f1dSLionel Sambuc if (!NumPids++) {
115*0a6a1f1dSLionel Sambuc PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
116*0a6a1f1dSLionel Sambuc if (PidLength <= 0)
117*0a6a1f1dSLionel Sambuc return -1;
118*0a6a1f1dSLionel Sambuc }
119*0a6a1f1dSLionel Sambuc if (!NumPids) {
120*0a6a1f1dSLionel Sambuc setFilename(Filename, 0);
121*0a6a1f1dSLionel Sambuc return 0;
122*0a6a1f1dSLionel Sambuc }
123*0a6a1f1dSLionel Sambuc
124*0a6a1f1dSLionel Sambuc /* Allocate enough space for the substituted filename. */
125*0a6a1f1dSLionel Sambuc char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
126*0a6a1f1dSLionel Sambuc if (!Allocated)
127*0a6a1f1dSLionel Sambuc return -1;
128*0a6a1f1dSLionel Sambuc
129*0a6a1f1dSLionel Sambuc /* Construct the new filename. */
130*0a6a1f1dSLionel Sambuc int J;
131*0a6a1f1dSLionel Sambuc for (I = 0, J = 0; Filename[I]; ++I)
132*0a6a1f1dSLionel Sambuc if (Filename[I] == '%') {
133*0a6a1f1dSLionel Sambuc if (Filename[++I] == 'p') {
134*0a6a1f1dSLionel Sambuc memcpy(Allocated + J, PidChars, PidLength);
135*0a6a1f1dSLionel Sambuc J += PidLength;
136*0a6a1f1dSLionel Sambuc }
137*0a6a1f1dSLionel Sambuc /* Drop any unknown substitutions. */
138*0a6a1f1dSLionel Sambuc } else
139*0a6a1f1dSLionel Sambuc Allocated[J++] = Filename[I];
140*0a6a1f1dSLionel Sambuc Allocated[J] = 0;
141*0a6a1f1dSLionel Sambuc
142*0a6a1f1dSLionel Sambuc /* Use the computed name. */
143*0a6a1f1dSLionel Sambuc setFilename(Allocated, 1);
144*0a6a1f1dSLionel Sambuc return 0;
145*0a6a1f1dSLionel Sambuc }
146*0a6a1f1dSLionel Sambuc
setFilenameAutomatically(void)147*0a6a1f1dSLionel Sambuc static void setFilenameAutomatically(void) {
148*0a6a1f1dSLionel Sambuc if (!setFilenameFromEnvironment())
149*0a6a1f1dSLionel Sambuc return;
150*0a6a1f1dSLionel Sambuc
151*0a6a1f1dSLionel Sambuc setDefaultFilename();
152*0a6a1f1dSLionel Sambuc }
153*0a6a1f1dSLionel Sambuc
154*0a6a1f1dSLionel Sambuc __attribute__((visibility("hidden")))
__llvm_profile_initialize_file(void)155*0a6a1f1dSLionel Sambuc void __llvm_profile_initialize_file(void) {
156*0a6a1f1dSLionel Sambuc /* Check if the filename has been initialized. */
157*0a6a1f1dSLionel Sambuc if (__llvm_profile_CurrentFilename)
158*0a6a1f1dSLionel Sambuc return;
159*0a6a1f1dSLionel Sambuc
160*0a6a1f1dSLionel Sambuc /* Detect the filename and truncate. */
161*0a6a1f1dSLionel Sambuc setFilenameAutomatically();
162*0a6a1f1dSLionel Sambuc truncateCurrentFile();
163*0a6a1f1dSLionel Sambuc }
164*0a6a1f1dSLionel Sambuc
165*0a6a1f1dSLionel Sambuc __attribute__((visibility("hidden")))
__llvm_profile_set_filename(const char * Filename)166*0a6a1f1dSLionel Sambuc void __llvm_profile_set_filename(const char *Filename) {
167*0a6a1f1dSLionel Sambuc setFilename(Filename, 0);
168*0a6a1f1dSLionel Sambuc truncateCurrentFile();
169*0a6a1f1dSLionel Sambuc }
170*0a6a1f1dSLionel Sambuc
171*0a6a1f1dSLionel Sambuc __attribute__((visibility("hidden")))
__llvm_profile_write_file(void)172*0a6a1f1dSLionel Sambuc int __llvm_profile_write_file(void) {
173*0a6a1f1dSLionel Sambuc /* Check the filename. */
174*0a6a1f1dSLionel Sambuc if (!__llvm_profile_CurrentFilename)
175*0a6a1f1dSLionel Sambuc return -1;
176*0a6a1f1dSLionel Sambuc
177*0a6a1f1dSLionel Sambuc /* Write the file. */
178*0a6a1f1dSLionel Sambuc return writeFileWithName(__llvm_profile_CurrentFilename);
179*0a6a1f1dSLionel Sambuc }
180*0a6a1f1dSLionel Sambuc
writeFileWithoutReturn(void)181*0a6a1f1dSLionel Sambuc static void writeFileWithoutReturn(void) {
182*0a6a1f1dSLionel Sambuc __llvm_profile_write_file();
183*0a6a1f1dSLionel Sambuc }
184*0a6a1f1dSLionel Sambuc
185*0a6a1f1dSLionel Sambuc __attribute__((visibility("hidden")))
__llvm_profile_register_write_file_atexit(void)186*0a6a1f1dSLionel Sambuc int __llvm_profile_register_write_file_atexit(void) {
187*0a6a1f1dSLionel Sambuc static int HasBeenRegistered = 0;
188*0a6a1f1dSLionel Sambuc
189*0a6a1f1dSLionel Sambuc if (HasBeenRegistered)
190*0a6a1f1dSLionel Sambuc return 0;
191*0a6a1f1dSLionel Sambuc
192*0a6a1f1dSLionel Sambuc HasBeenRegistered = 1;
193*0a6a1f1dSLionel Sambuc return atexit(writeFileWithoutReturn);
194*0a6a1f1dSLionel Sambuc }
195