/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include #include #include static int writeFile(FILE *File) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_data_begin(); const __llvm_profile_data *DataEnd = __llvm_profile_data_end(); const uint64_t *CountersBegin = __llvm_profile_counters_begin(); const uint64_t *CountersEnd = __llvm_profile_counters_end(); const char *NamesBegin = __llvm_profile_names_begin(); const char *NamesEnd = __llvm_profile_names_end(); /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; /* Create the header. */ uint64_t Header[PROFILE_HEADER_SIZE] = { __llvm_profile_get_magic(), __llvm_profile_get_version(), DataSize, CountersSize, NamesSize, (uintptr_t)CountersBegin, (uintptr_t)NamesBegin }; /* Write the data. */ #define CHECK_fwrite(Data, Size, Length, File) \ do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0) CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File); CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File); CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File); CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File); #undef CHECK_fwrite return 0; } static int writeFileWithName(const char *OutputName) { int RetVal; FILE *OutputFile; if (!OutputName || !OutputName[0]) return -1; OutputFile = fopen(OutputName, "w"); if (!OutputFile) return -1; RetVal = writeFile(OutputFile); fclose(OutputFile); return RetVal; } static const char *CurrentFilename = NULL; void __llvm_profile_set_filename(const char *Filename) { CurrentFilename = Filename; } int getpid(void); int __llvm_profile_write_file(void) { char *AllocatedFilename = NULL; int I, J; int RetVal; #define MAX_PID_SIZE 16 char PidChars[MAX_PID_SIZE] = { 0 }; int PidLength = 0; int NumPids = 0; /* Get the filename. */ const char *Filename = CurrentFilename; #define UPDATE_FILENAME(NextFilename) \ if (!Filename || !Filename[0]) Filename = NextFilename UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE")); UPDATE_FILENAME("default.profraw"); #undef UPDATE_FILENAME /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; Filename[I]; ++I) if (Filename[I] == '%' && Filename[++I] == 'p') if (!NumPids++) { PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); if (PidLength <= 0) return -1; } if (NumPids) { /* Allocate enough space for the substituted filename. */ AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1); if (!AllocatedFilename) return -1; /* Construct the new filename. */ for (I = 0, J = 0; Filename[I]; ++I) if (Filename[I] == '%') { if (Filename[++I] == 'p') { memcpy(AllocatedFilename + J, PidChars, PidLength); J += PidLength; } /* Drop any unknown substitutions. */ } else AllocatedFilename[J++] = Filename[I]; AllocatedFilename[J] = 0; /* Actually use the computed name. */ Filename = AllocatedFilename; } /* Write the file. */ RetVal = writeFileWithName(Filename); /* Free the filename. */ if (AllocatedFilename) free(AllocatedFilename); return RetVal; } static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } int __llvm_profile_register_write_file_atexit(void) { static int HasBeenRegistered = 0; if (HasBeenRegistered) return 0; HasBeenRegistered = 1; return atexit(writeFileWithoutReturn); }