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 #include <sys/errno.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 setFilename(const char *Filename, int OwnsFilename) { 80 if (__llvm_profile_OwnsFilename) 81 free(UNCONST(__llvm_profile_CurrentFilename)); 82 83 __llvm_profile_CurrentFilename = Filename; 84 __llvm_profile_OwnsFilename = OwnsFilename; 85 } 86 87 static void truncateCurrentFile(void) { 88 const char *Filename = __llvm_profile_CurrentFilename; 89 if (!Filename || !Filename[0]) 90 return; 91 92 /* Truncate the file. Later we'll reopen and append. */ 93 FILE *File = fopen(Filename, "w"); 94 if (!File) 95 return; 96 fclose(File); 97 } 98 99 static void setDefaultFilename(void) { setFilename("default.profraw", 0); } 100 101 int getpid(void); 102 static int setFilenameFromEnvironment(void) { 103 const char *Filename = getenv("LLVM_PROFILE_FILE"); 104 if (!Filename || !Filename[0]) 105 return -1; 106 107 /* Check the filename for "%p", which indicates a pid-substitution. */ 108 #define MAX_PID_SIZE 16 109 char PidChars[MAX_PID_SIZE] = {0}; 110 int NumPids = 0; 111 int PidLength = 0; 112 int I; 113 for (I = 0; Filename[I]; ++I) 114 if (Filename[I] == '%' && Filename[++I] == 'p') 115 if (!NumPids++) { 116 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); 117 if (PidLength <= 0) 118 return -1; 119 } 120 if (!NumPids) { 121 setFilename(Filename, 0); 122 return 0; 123 } 124 125 /* Allocate enough space for the substituted filename. */ 126 char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1); 127 if (!Allocated) 128 return -1; 129 130 /* Construct the new filename. */ 131 int J; 132 for (I = 0, J = 0; Filename[I]; ++I) 133 if (Filename[I] == '%') { 134 if (Filename[++I] == 'p') { 135 memcpy(Allocated + J, PidChars, PidLength); 136 J += PidLength; 137 } 138 /* Drop any unknown substitutions. */ 139 } else 140 Allocated[J++] = Filename[I]; 141 Allocated[J] = 0; 142 143 /* Use the computed name. */ 144 setFilename(Allocated, 1); 145 return 0; 146 } 147 148 static void setFilenameAutomatically(void) { 149 if (!setFilenameFromEnvironment()) 150 return; 151 152 setDefaultFilename(); 153 } 154 155 __attribute__((visibility("hidden"))) 156 void __llvm_profile_initialize_file(void) { 157 /* Check if the filename has been initialized. */ 158 if (__llvm_profile_CurrentFilename) 159 return; 160 161 /* Detect the filename and truncate. */ 162 setFilenameAutomatically(); 163 truncateCurrentFile(); 164 } 165 166 __attribute__((visibility("hidden"))) 167 void __llvm_profile_set_filename(const char *Filename) { 168 setFilename(Filename, 0); 169 truncateCurrentFile(); 170 } 171 172 __attribute__((visibility("hidden"))) 173 int __llvm_profile_write_file(void) { 174 /* Check the filename. */ 175 if (!__llvm_profile_CurrentFilename) 176 return -1; 177 178 /* Write the file. */ 179 int rc = writeFileWithName(__llvm_profile_CurrentFilename); 180 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS")) 181 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n", 182 __llvm_profile_CurrentFilename, strerror(errno)); 183 return rc; 184 } 185 186 static void writeFileWithoutReturn(void) { 187 __llvm_profile_write_file(); 188 } 189 190 __attribute__((visibility("hidden"))) 191 int __llvm_profile_register_write_file_atexit(void) { 192 static int HasBeenRegistered = 0; 193 194 if (HasBeenRegistered) 195 return 0; 196 197 HasBeenRegistered = 1; 198 return atexit(writeFileWithoutReturn); 199 } 200