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 29 /* Create the header. */ 30 uint64_t Header[PROFILE_HEADER_SIZE] = { 31 __llvm_profile_get_magic(), 32 __llvm_profile_get_version(), 33 DataSize, 34 CountersSize, 35 NamesSize, 36 (uintptr_t)CountersBegin, 37 (uintptr_t)NamesBegin 38 }; 39 40 /* Write the data. */ 41 #define CHECK_fwrite(Data, Size, Length, File) \ 42 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0) 43 CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File); 44 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File); 45 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File); 46 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File); 47 #undef CHECK_fwrite 48 49 return 0; 50 } 51 52 static int writeFileWithName(const char *OutputName) { 53 int RetVal; 54 FILE *OutputFile; 55 if (!OutputName || !OutputName[0]) 56 return -1; 57 OutputFile = fopen(OutputName, "w"); 58 if (!OutputFile) 59 return -1; 60 61 RetVal = writeFile(OutputFile); 62 63 fclose(OutputFile); 64 return RetVal; 65 } 66 67 static const char *CurrentFilename = NULL; 68 void __llvm_profile_set_filename(const char *Filename) { 69 CurrentFilename = Filename; 70 } 71 72 int getpid(void); 73 int __llvm_profile_write_file(void) { 74 char *AllocatedFilename = NULL; 75 int I, J; 76 int RetVal; 77 78 #define MAX_PID_SIZE 16 79 char PidChars[MAX_PID_SIZE] = { 0 }; 80 int PidLength = 0; 81 int NumPids = 0; 82 83 /* Get the filename. */ 84 const char *Filename = CurrentFilename; 85 #define UPDATE_FILENAME(NextFilename) \ 86 if (!Filename || !Filename[0]) Filename = NextFilename 87 UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE")); 88 UPDATE_FILENAME("default.profraw"); 89 #undef UPDATE_FILENAME 90 91 /* Check the filename for "%p", which indicates a pid-substitution. */ 92 for (I = 0; Filename[I]; ++I) 93 if (Filename[I] == '%' && Filename[++I] == 'p') 94 if (!NumPids++) { 95 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); 96 if (PidLength <= 0) 97 return -1; 98 } 99 if (NumPids) { 100 /* Allocate enough space for the substituted filename. */ 101 AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1); 102 if (!AllocatedFilename) 103 return -1; 104 105 /* Construct the new filename. */ 106 for (I = 0, J = 0; Filename[I]; ++I) 107 if (Filename[I] == '%') { 108 if (Filename[++I] == 'p') { 109 memcpy(AllocatedFilename + J, PidChars, PidLength); 110 J += PidLength; 111 } 112 /* Drop any unknown substitutions. */ 113 } else 114 AllocatedFilename[J++] = Filename[I]; 115 AllocatedFilename[J] = 0; 116 117 /* Actually use the computed name. */ 118 Filename = AllocatedFilename; 119 } 120 121 /* Write the file. */ 122 RetVal = writeFileWithName(Filename); 123 124 /* Free the filename. */ 125 if (AllocatedFilename) 126 free(AllocatedFilename); 127 128 return RetVal; 129 } 130 131 static void writeFileWithoutReturn(void) { 132 __llvm_profile_write_file(); 133 } 134 135 int __llvm_profile_register_write_file_atexit(void) { 136 static int HasBeenRegistered = 0; 137 138 if (HasBeenRegistered) 139 return 0; 140 141 HasBeenRegistered = 1; 142 return atexit(writeFileWithoutReturn); 143 } 144