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