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