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