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