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 __llvm_profile_header Header; 39 Header.Magic = __llvm_profile_get_magic(); 40 Header.Version = __llvm_profile_get_version(); 41 Header.DataSize = DataSize; 42 Header.CountersSize = CountersSize; 43 Header.NamesSize = NamesSize; 44 Header.CountersDelta = (uintptr_t)CountersBegin; 45 Header.NamesDelta = (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(__llvm_profile_header), 1, 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 free(Copy); 94 } 95 96 /* Truncate the file. Later we'll reopen and append. */ 97 File = fopen(Filename, "w"); 98 if (!File) 99 return; 100 fclose(File); 101 } 102 103 static void setFilename(const char *Filename, int OwnsFilename) { 104 /* Check if this is a new filename and therefore needs truncation. */ 105 int NewFile = !__llvm_profile_CurrentFilename || 106 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); 107 if (__llvm_profile_OwnsFilename) 108 free(UNCONST(__llvm_profile_CurrentFilename)); 109 110 __llvm_profile_CurrentFilename = Filename; 111 __llvm_profile_OwnsFilename = OwnsFilename; 112 113 /* If not a new file, append to support profiling multiple shared objects. */ 114 if (NewFile) 115 truncateCurrentFile(); 116 } 117 118 static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } 119 120 int getpid(void); 121 static int setFilenamePossiblyWithPid(const char *Filename) { 122 #define MAX_PID_SIZE 16 123 char PidChars[MAX_PID_SIZE] = {0}; 124 int NumPids = 0, PidLength = 0; 125 char *Allocated; 126 int I, J; 127 128 /* Reset filename on NULL, except with env var which is checked by caller. */ 129 if (!Filename) { 130 resetFilenameToDefault(); 131 return 0; 132 } 133 134 /* Check the filename for "%p", which indicates a pid-substitution. */ 135 for (I = 0; Filename[I]; ++I) 136 if (Filename[I] == '%' && Filename[++I] == 'p') 137 if (!NumPids++) { 138 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); 139 if (PidLength <= 0) 140 return -1; 141 } 142 if (!NumPids) { 143 setFilename(Filename, 0); 144 return 0; 145 } 146 147 /* Allocate enough space for the substituted filename. */ 148 Allocated = malloc(I + NumPids*(PidLength - 2) + 1); 149 if (!Allocated) 150 return -1; 151 152 /* Construct the new filename. */ 153 for (I = 0, J = 0; Filename[I]; ++I) 154 if (Filename[I] == '%') { 155 if (Filename[++I] == 'p') { 156 memcpy(Allocated + J, PidChars, PidLength); 157 J += PidLength; 158 } 159 /* Drop any unknown substitutions. */ 160 } else 161 Allocated[J++] = Filename[I]; 162 Allocated[J] = 0; 163 164 /* Use the computed name. */ 165 setFilename(Allocated, 1); 166 return 0; 167 } 168 169 static int setFilenameFromEnvironment(void) { 170 const char *Filename = getenv("LLVM_PROFILE_FILE"); 171 172 if (!Filename || !Filename[0]) 173 return -1; 174 175 return setFilenamePossiblyWithPid(Filename); 176 } 177 178 static void setFilenameAutomatically(void) { 179 if (!setFilenameFromEnvironment()) 180 return; 181 182 resetFilenameToDefault(); 183 } 184 185 __attribute__((visibility("hidden"))) 186 void __llvm_profile_initialize_file(void) { 187 /* Check if the filename has been initialized. */ 188 if (__llvm_profile_CurrentFilename) 189 return; 190 191 /* Detect the filename and truncate. */ 192 setFilenameAutomatically(); 193 } 194 195 __attribute__((visibility("hidden"))) 196 void __llvm_profile_set_filename(const char *Filename) { 197 setFilenamePossiblyWithPid(Filename); 198 } 199 200 __attribute__((visibility("hidden"))) 201 void __llvm_profile_override_default_filename(const char *Filename) { 202 /* If the env var is set, skip setting filename from argument. */ 203 const char *Env_Filename = getenv("LLVM_PROFILE_FILE"); 204 if (Env_Filename && Env_Filename[0]) 205 return; 206 setFilenamePossiblyWithPid(Filename); 207 } 208 209 __attribute__((visibility("hidden"))) 210 int __llvm_profile_write_file(void) { 211 int rc; 212 213 /* Check the filename. */ 214 if (!__llvm_profile_CurrentFilename) 215 return -1; 216 217 /* Write the file. */ 218 rc = writeFileWithName(__llvm_profile_CurrentFilename); 219 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS")) 220 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n", 221 __llvm_profile_CurrentFilename, strerror(errno)); 222 return rc; 223 } 224 225 static void writeFileWithoutReturn(void) { 226 __llvm_profile_write_file(); 227 } 228 229 __attribute__((visibility("hidden"))) 230 int __llvm_profile_register_write_file_atexit(void) { 231 static int HasBeenRegistered = 0; 232 233 if (HasBeenRegistered) 234 return 0; 235 236 HasBeenRegistered = 1; 237 return atexit(writeFileWithoutReturn); 238 } 239