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 "InstrProfilingUtil.h" 12 #include <errno.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) 18 19 static int writeFile(FILE *File) { 20 /* Match logic in __llvm_profile_write_buffer(). */ 21 const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 22 const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 23 const uint64_t *CountersBegin = __llvm_profile_begin_counters(); 24 const uint64_t *CountersEnd = __llvm_profile_end_counters(); 25 const char *NamesBegin = __llvm_profile_begin_names(); 26 const char *NamesEnd = __llvm_profile_end_names(); 27 28 /* Calculate size of sections. */ 29 const uint64_t DataSize = DataEnd - DataBegin; 30 const uint64_t CountersSize = CountersEnd - CountersBegin; 31 const uint64_t NamesSize = NamesEnd - NamesBegin; 32 const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); 33 34 /* Enough zeroes for padding. */ 35 const char Zeroes[sizeof(uint64_t)] = {0}; 36 37 /* Create the header. */ 38 uint64_t Header[PROFILE_HEADER_SIZE]; 39 Header[0] = __llvm_profile_get_magic(); 40 Header[1] = __llvm_profile_get_version(); 41 Header[2] = DataSize; 42 Header[3] = CountersSize; 43 Header[4] = NamesSize; 44 Header[5] = (uintptr_t)CountersBegin; 45 Header[6] = (uintptr_t)NamesBegin; 46 47 /* Write the data. */ 48 #define CHECK_fwrite(Data, Size, Length, File) \ 49 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0) 50 CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File); 51 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File); 52 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File); 53 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File); 54 CHECK_fwrite(Zeroes, sizeof(char), Padding, File); 55 #undef CHECK_fwrite 56 57 return 0; 58 } 59 60 static int writeFileWithName(const char *OutputName) { 61 int RetVal; 62 FILE *OutputFile; 63 if (!OutputName || !OutputName[0]) 64 return -1; 65 66 /* Append to the file to support profiling multiple shared objects. */ 67 OutputFile = fopen(OutputName, "a"); 68 if (!OutputFile) 69 return -1; 70 71 RetVal = writeFile(OutputFile); 72 73 fclose(OutputFile); 74 return RetVal; 75 } 76 77 __attribute__((weak)) int __llvm_profile_OwnsFilename = 0; 78 __attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL; 79 80 static void truncateCurrentFile(void) { 81 const char *Filename; 82 FILE *File; 83 84 Filename = __llvm_profile_CurrentFilename; 85 if (!Filename || !Filename[0]) 86 return; 87 88 /* Create the directory holding the file, if needed. */ 89 if (strchr(Filename, '/')) { 90 char *Copy = malloc(strlen(Filename) + 1); 91 strcpy(Copy, Filename); 92 __llvm_profile_recursive_mkdir(Copy); 93 } 94 95 /* Truncate the file. Later we'll reopen and append. */ 96 File = fopen(Filename, "w"); 97 if (!File) 98 return; 99 fclose(File); 100 } 101 102 static void setFilename(const char *Filename, int OwnsFilename) { 103 /* Check if this is a new filename and therefore needs truncation. */ 104 int NewFile = !__llvm_profile_CurrentFilename || 105 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); 106 if (__llvm_profile_OwnsFilename) 107 free(UNCONST(__llvm_profile_CurrentFilename)); 108 109 __llvm_profile_CurrentFilename = Filename; 110 __llvm_profile_OwnsFilename = OwnsFilename; 111 112 /* If not a new file, append to support profiling multiple shared objects. */ 113 if (NewFile) 114 truncateCurrentFile(); 115 } 116 117 static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } 118 119 int getpid(void); 120 static int setFilenamePossiblyWithPid(const char *Filename) { 121 #define MAX_PID_SIZE 16 122 char PidChars[MAX_PID_SIZE] = {0}; 123 int NumPids = 0, PidLength = 0; 124 char *Allocated; 125 int I, J; 126 127 /* Reset filename on NULL, except with env var which is checked by caller. */ 128 if (!Filename) { 129 resetFilenameToDefault(); 130 return 0; 131 } 132 133 /* Check the filename for "%p", which indicates a pid-substitution. */ 134 for (I = 0; Filename[I]; ++I) 135 if (Filename[I] == '%' && Filename[++I] == 'p') 136 if (!NumPids++) { 137 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); 138 if (PidLength <= 0) 139 return -1; 140 } 141 if (!NumPids) { 142 setFilename(Filename, 0); 143 return 0; 144 } 145 146 /* Allocate enough space for the substituted filename. */ 147 Allocated = malloc(I + NumPids*(PidLength - 2) + 1); 148 if (!Allocated) 149 return -1; 150 151 /* Construct the new filename. */ 152 for (I = 0, J = 0; Filename[I]; ++I) 153 if (Filename[I] == '%') { 154 if (Filename[++I] == 'p') { 155 memcpy(Allocated + J, PidChars, PidLength); 156 J += PidLength; 157 } 158 /* Drop any unknown substitutions. */ 159 } else 160 Allocated[J++] = Filename[I]; 161 Allocated[J] = 0; 162 163 /* Use the computed name. */ 164 setFilename(Allocated, 1); 165 return 0; 166 } 167 168 static int setFilenameFromEnvironment(void) { 169 const char *Filename = getenv("LLVM_PROFILE_FILE"); 170 171 if (!Filename || !Filename[0]) 172 return -1; 173 174 return setFilenamePossiblyWithPid(Filename); 175 } 176 177 static void setFilenameAutomatically(void) { 178 if (!setFilenameFromEnvironment()) 179 return; 180 181 resetFilenameToDefault(); 182 } 183 184 __attribute__((visibility("hidden"))) 185 void __llvm_profile_initialize_file(void) { 186 /* Check if the filename has been initialized. */ 187 if (__llvm_profile_CurrentFilename) 188 return; 189 190 /* Detect the filename and truncate. */ 191 setFilenameAutomatically(); 192 } 193 194 __attribute__((visibility("hidden"))) 195 void __llvm_profile_set_filename(const char *Filename) { 196 setFilenamePossiblyWithPid(Filename); 197 } 198 199 __attribute__((visibility("hidden"))) 200 void __llvm_profile_override_default_filename(const char *Filename) { 201 /* If the env var is set, skip setting filename from argument. */ 202 const char *Env_Filename = getenv("LLVM_PROFILE_FILE"); 203 if (Env_Filename && Env_Filename[0]) 204 return; 205 setFilenamePossiblyWithPid(Filename); 206 } 207 208 __attribute__((visibility("hidden"))) 209 int __llvm_profile_write_file(void) { 210 int rc; 211 212 /* Check the filename. */ 213 if (!__llvm_profile_CurrentFilename) 214 return -1; 215 216 /* Write the file. */ 217 rc = writeFileWithName(__llvm_profile_CurrentFilename); 218 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS")) 219 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n", 220 __llvm_profile_CurrentFilename, strerror(errno)); 221 return rc; 222 } 223 224 static void writeFileWithoutReturn(void) { 225 __llvm_profile_write_file(); 226 } 227 228 __attribute__((visibility("hidden"))) 229 int __llvm_profile_register_write_file_atexit(void) { 230 static int HasBeenRegistered = 0; 231 232 if (HasBeenRegistered) 233 return 0; 234 235 HasBeenRegistered = 1; 236 return atexit(writeFileWithoutReturn); 237 } 238