Path: blob/main/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c
7088 views
/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\1|*2|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3|* See https://llvm.org/LICENSE.txt for license information.4|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5|*6\*===----------------------------------------------------------------------===*/78#if !defined(__Fuchsia__)910#include <assert.h>11#include <errno.h>12#include <stdio.h>13#include <stdlib.h>14#include <string.h>15#ifdef _MSC_VER16/* For _alloca. */17#include <malloc.h>18#endif19#if defined(_WIN32)20#include "WindowsMMap.h"21/* For _chsize_s */22#include <io.h>23#include <process.h>24#else25#include <sys/file.h>26#include <sys/mman.h>27#include <unistd.h>28#if defined(__linux__)29#include <sys/types.h>30#endif31#endif3233#include "InstrProfiling.h"34#include "InstrProfilingInternal.h"35#include "InstrProfilingPort.h"36#include "InstrProfilingUtil.h"3738/* From where is profile name specified.39* The order the enumerators define their40* precedence. Re-order them may lead to41* runtime behavior change. */42typedef enum ProfileNameSpecifier {43PNS_unknown = 0,44PNS_default,45PNS_command_line,46PNS_environment,47PNS_runtime_api48} ProfileNameSpecifier;4950static const char *getPNSStr(ProfileNameSpecifier PNS) {51switch (PNS) {52case PNS_default:53return "default setting";54case PNS_command_line:55return "command line";56case PNS_environment:57return "environment variable";58case PNS_runtime_api:59return "runtime API";60default:61return "Unknown";62}63}6465#define MAX_PID_SIZE 1666/* Data structure holding the result of parsed filename pattern. */67typedef struct lprofFilename {68/* File name string possibly with %p or %h specifiers. */69const char *FilenamePat;70/* A flag indicating if FilenamePat's memory is allocated71* by runtime. */72unsigned OwnsFilenamePat;73const char *ProfilePathPrefix;74char PidChars[MAX_PID_SIZE];75char *TmpDir;76char Hostname[COMPILER_RT_MAX_HOSTLEN];77unsigned NumPids;78unsigned NumHosts;79unsigned NumBinaryIds;80/* When in-process merging is enabled, this parameter specifies81* the total number of profile data files shared by all the processes82* spawned from the same binary. By default the value is 1. If merging83* is not enabled, its value should be 0. This parameter is specified84* by the %[0-9]m specifier. For instance %2m enables merging using85* 2 profile data files. %1m is equivalent to %m. Also %m specifier86* can only appear once at the end of the name pattern. */87unsigned MergePoolSize;88ProfileNameSpecifier PNS;89} lprofFilename;9091static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, {0},920, 0, 0, 0, PNS_unknown};9394static int ProfileMergeRequested = 0;95static int getProfileFileSizeForMerging(FILE *ProfileFile,96uint64_t *ProfileFileSize);9798#if defined(__APPLE__)99static const int ContinuousModeSupported = 1;100static const int UseBiasVar = 0;101static const char *FileOpenMode = "a+b";102static void *BiasAddr = NULL;103static void *BiasDefaultAddr = NULL;104static void *BitmapBiasAddr = NULL;105static void *BitmapBiasDefaultAddr = NULL;106static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {107/* Get the sizes of various profile data sections. Taken from108* __llvm_profile_get_size_for_buffer(). */109const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();110const __llvm_profile_data *DataEnd = __llvm_profile_end_data();111const char *CountersBegin = __llvm_profile_begin_counters();112const char *CountersEnd = __llvm_profile_end_counters();113const char *BitmapBegin = __llvm_profile_begin_bitmap();114const char *BitmapEnd = __llvm_profile_end_bitmap();115const char *NamesBegin = __llvm_profile_begin_names();116const char *NamesEnd = __llvm_profile_end_names();117const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);118uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);119uint64_t CountersSize =120__llvm_profile_get_counters_size(CountersBegin, CountersEnd);121uint64_t NumBitmapBytes =122__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);123124/* Check that the counter, bitmap, and data sections in this image are125* page-aligned. */126unsigned PageSize = getpagesize();127if ((intptr_t)CountersBegin % PageSize != 0) {128PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",129CountersBegin, PageSize);130return 1;131}132if ((intptr_t)BitmapBegin % PageSize != 0) {133PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",134BitmapBegin, PageSize);135return 1;136}137if ((intptr_t)DataBegin % PageSize != 0) {138PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",139DataBegin, PageSize);140return 1;141}142143int Fileno = fileno(File);144/* Determine how much padding is needed before/after the counters and145* after the names. */146uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,147PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,148PaddingBytesAfterVTable, PaddingBytesAfterVNames;149__llvm_profile_get_padding_sizes_for_counters(150DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0,151/*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,152&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames,153&PaddingBytesAfterVTable, &PaddingBytesAfterVNames);154155uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;156uint64_t FileOffsetToCounters = CurrentFileOffset +157sizeof(__llvm_profile_header) + DataSize +158PaddingBytesBeforeCounters;159void *CounterMmap = mmap((void *)CountersBegin, PageAlignedCountersLength,160PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,161Fileno, FileOffsetToCounters);162if (CounterMmap != CountersBegin) {163PROF_ERR(164"Continuous counter sync mode is enabled, but mmap() failed (%s).\n"165" - CountersBegin: %p\n"166" - PageAlignedCountersLength: %" PRIu64 "\n"167" - Fileno: %d\n"168" - FileOffsetToCounters: %" PRIu64 "\n",169strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,170FileOffsetToCounters);171return 1;172}173174/* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()175* will fail with EINVAL. */176if (NumBitmapBytes == 0)177return 0;178179uint64_t PageAlignedBitmapLength =180NumBitmapBytes + PaddingBytesAfterBitmapBytes;181uint64_t FileOffsetToBitmap =182FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;183void *BitmapMmap =184mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE,185MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap);186if (BitmapMmap != BitmapBegin) {187PROF_ERR(188"Continuous counter sync mode is enabled, but mmap() failed (%s).\n"189" - BitmapBegin: %p\n"190" - PageAlignedBitmapLength: %" PRIu64 "\n"191" - Fileno: %d\n"192" - FileOffsetToBitmap: %" PRIu64 "\n",193strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno,194FileOffsetToBitmap);195return 1;196}197return 0;198}199#elif defined(__ELF__) || defined(_WIN32) || defined(_AIX)200201#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \202INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)203COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0;204#define INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR \205INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_BITMAP_BIAS_VAR, _default)206COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR = 0;207208/* This variable is a weak external reference which could be used to detect209* whether or not the compiler defined this symbol. */210#if defined(_MSC_VER)211COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;212COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;213#if defined(_M_IX86) || defined(__i386__)214#define WIN_SYM_PREFIX "_"215#else216#define WIN_SYM_PREFIX217#endif218#pragma comment( \219linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \220INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \221INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))222#pragma comment( \223linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \224INSTR_PROF_PROFILE_BITMAP_BIAS_VAR) "=" WIN_SYM_PREFIX \225INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))226#else227COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR228__attribute__((weak, alias(INSTR_PROF_QUOTE(229INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))));230COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR231__attribute__((weak, alias(INSTR_PROF_QUOTE(232INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))));233#endif234static const int ContinuousModeSupported = 1;235static const int UseBiasVar = 1;236/* TODO: If there are two DSOs, the second DSO initialization will truncate the237* first profile file. */238static const char *FileOpenMode = "w+b";239/* This symbol is defined by the compiler when runtime counter relocation is240* used and runtime provides a weak alias so we can check if it's defined. */241static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;242static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR;243static void *BitmapBiasAddr = &INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;244static void *BitmapBiasDefaultAddr =245&INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR;246static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {247/* Get the sizes of various profile data sections. Taken from248* __llvm_profile_get_size_for_buffer(). */249const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();250const __llvm_profile_data *DataEnd = __llvm_profile_end_data();251const char *CountersBegin = __llvm_profile_begin_counters();252const char *CountersEnd = __llvm_profile_end_counters();253const char *BitmapBegin = __llvm_profile_begin_bitmap();254const char *BitmapEnd = __llvm_profile_end_bitmap();255uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);256uint64_t CountersSize =257__llvm_profile_get_counters_size(CountersBegin, CountersEnd);258uint64_t NumBitmapBytes =259__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);260/* Get the file size. */261uint64_t FileSize = 0;262if (getProfileFileSizeForMerging(File, &FileSize))263return 1;264265int Fileno = fileno(File);266uint64_t PaddingBytesAfterCounters =267__llvm_profile_get_num_padding_bytes(CountersSize);268uint64_t FileOffsetToCounters =269sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize;270271/* Map the profile. */272char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE,273MAP_SHARED, Fileno, 0);274if (Profile == MAP_FAILED) {275PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));276return 1;277}278/* Update the profile fields based on the current mapping. */279INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =280(intptr_t)Profile - (uintptr_t)CountersBegin + FileOffsetToCounters;281282/* Return the memory allocated for counters to OS. */283lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);284285/* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()286* will fail with EINVAL. */287if (NumBitmapBytes == 0)288return 0;289290/* Update profbm_bias. */291uint64_t FileOffsetToBitmap =292FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;293/* Update the profile fields based on the current mapping. */294INSTR_PROF_PROFILE_BITMAP_BIAS_VAR =295(uintptr_t)Profile - (uintptr_t)BitmapBegin + FileOffsetToBitmap;296297/* Return the memory allocated for counters to OS. */298lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd);299return 0;300}301#else302static const int ContinuousModeSupported = 0;303static const int UseBiasVar = 0;304static const char *FileOpenMode = "a+b";305static void *BiasAddr = NULL;306static void *BiasDefaultAddr = NULL;307static void *BitmapBiasAddr = NULL;308static void *BitmapBiasDefaultAddr = NULL;309static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {310return 0;311}312#endif313314static int isProfileMergeRequested(void) { return ProfileMergeRequested; }315static void setProfileMergeRequested(int EnableMerge) {316ProfileMergeRequested = EnableMerge;317}318319static FILE *ProfileFile = NULL;320static FILE *getProfileFile(void) { return ProfileFile; }321static void setProfileFile(FILE *File) { ProfileFile = File; }322323static int getCurFilenameLength(void);324static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);325static unsigned doMerging(void) {326return lprofCurFilename.MergePoolSize || isProfileMergeRequested();327}328329/* Return 1 if there is an error, otherwise return 0. */330static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,331uint32_t NumIOVecs) {332uint32_t I;333FILE *File = (FILE *)This->WriterCtx;334char Zeroes[sizeof(uint64_t)] = {0};335for (I = 0; I < NumIOVecs; I++) {336if (IOVecs[I].Data) {337if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=338IOVecs[I].NumElm)339return 1;340} else if (IOVecs[I].UseZeroPadding) {341size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm;342while (BytesToWrite > 0) {343size_t PartialWriteLen =344(sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t);345if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) !=346PartialWriteLen) {347return 1;348}349BytesToWrite -= PartialWriteLen;350}351} else {352if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)353return 1;354}355}356return 0;357}358359static void initFileWriter(ProfDataWriter *This, FILE *File) {360This->Write = fileWriter;361This->WriterCtx = File;362}363364COMPILER_RT_VISIBILITY ProfBufferIO *365lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {366FreeHook = &free;367DynamicBufferIOBuffer = (uint8_t *)calloc(1, BufferSz);368VPBufferSize = BufferSz;369ProfDataWriter *fileWriter =370(ProfDataWriter *)calloc(1, sizeof(ProfDataWriter));371initFileWriter(fileWriter, File);372ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);373IO->OwnFileWriter = 1;374return IO;375}376377static void setupIOBuffer(void) {378const char *BufferSzStr = 0;379BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");380if (BufferSzStr && BufferSzStr[0]) {381VPBufferSize = atoi(BufferSzStr);382DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);383}384}385386/* Get the size of the profile file. If there are any errors, print the387* message under the assumption that the profile is being read for merging388* purposes, and return -1. Otherwise return the file size in the inout param389* \p ProfileFileSize. */390static int getProfileFileSizeForMerging(FILE *ProfileFile,391uint64_t *ProfileFileSize) {392if (fseek(ProfileFile, 0L, SEEK_END) == -1) {393PROF_ERR("Unable to merge profile data, unable to get size: %s\n",394strerror(errno));395return -1;396}397*ProfileFileSize = ftell(ProfileFile);398399/* Restore file offset. */400if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {401PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",402strerror(errno));403return -1;404}405406if (*ProfileFileSize > 0 &&407*ProfileFileSize < sizeof(__llvm_profile_header)) {408PROF_WARN("Unable to merge profile data: %s\n",409"source profile file is too small.");410return -1;411}412return 0;413}414415/* mmap() \p ProfileFile for profile merging purposes, assuming that an416* exclusive lock is held on the file and that \p ProfileFileSize is the417* length of the file. Return the mmap'd buffer in the inout variable418* \p ProfileBuffer. Returns -1 on failure. On success, the caller is419* responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */420static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,421ManagedMemory *ProfileBuffer) {422lprofGetFileContentBuffer(ProfileFile, ProfileFileSize, ProfileBuffer);423424if (ProfileBuffer->Status == MS_INVALID) {425PROF_ERR("Unable to merge profile data: %s\n", "reading file failed");426return -1;427}428429if (__llvm_profile_check_compatibility(ProfileBuffer->Addr,430ProfileFileSize)) {431(void)lprofReleaseBuffer(ProfileBuffer, ProfileFileSize);432PROF_WARN("Unable to merge profile data: %s\n",433"source profile file is not compatible.");434return -1;435}436return 0;437}438439/* Read profile data in \c ProfileFile and merge with in-memory440profile counters. Returns -1 if there is fatal error, otherwise4410 is returned. Returning 0 does not mean merge is actually442performed. If merge is actually done, *MergeDone is set to 1.443*/444static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {445uint64_t ProfileFileSize;446ManagedMemory ProfileBuffer;447448/* Get the size of the profile on disk. */449if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1)450return -1;451452/* Nothing to merge. */453if (!ProfileFileSize)454return 0;455456/* mmap() the profile and check that it is compatible with the data in457* the current image. */458if (mmapProfileForMerging(ProfileFile, ProfileFileSize, &ProfileBuffer) == -1)459return -1;460461/* Now start merging */462if (__llvm_profile_merge_from_buffer(ProfileBuffer.Addr, ProfileFileSize)) {463PROF_ERR("%s\n", "Invalid profile data to merge");464(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);465return -1;466}467468// Truncate the file in case merging of value profile did not happen to469// prevent from leaving garbage data at the end of the profile file.470(void)COMPILER_RT_FTRUNCATE(ProfileFile,471__llvm_profile_get_size_for_buffer());472473(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);474*MergeDone = 1;475476return 0;477}478479/* Create the directory holding the file, if needed. */480static void createProfileDir(const char *Filename) {481size_t Length = strlen(Filename);482if (lprofFindFirstDirSeparator(Filename)) {483char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);484strncpy(Copy, Filename, Length + 1);485__llvm_profile_recursive_mkdir(Copy);486}487}488489/* Open the profile data for merging. It opens the file in r+b mode with490* file locking. If the file has content which is compatible with the491* current process, it also reads in the profile data in the file and merge492* it with in-memory counters. After the profile data is merged in memory,493* the original profile data is truncated and gets ready for the profile494* dumper. With profile merging enabled, each executable as well as any of495* its instrumented shared libraries dump profile data into their own data file.496*/497static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {498FILE *ProfileFile = getProfileFile();499int rc;500// initializeProfileForContinuousMode will lock the profile, but if501// ProfileFile is set by user via __llvm_profile_set_file_object, it's assumed502// unlocked at this point.503if (ProfileFile && !__llvm_profile_is_continuous_mode_enabled()) {504lprofLockFileHandle(ProfileFile);505}506if (!ProfileFile) {507createProfileDir(ProfileFileName);508ProfileFile = lprofOpenFileEx(ProfileFileName);509}510if (!ProfileFile)511return NULL;512513rc = doProfileMerging(ProfileFile, MergeDone);514if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||515fseek(ProfileFile, 0L, SEEK_SET) == -1) {516PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,517strerror(errno));518fclose(ProfileFile);519return NULL;520}521return ProfileFile;522}523524static FILE *getFileObject(const char *OutputName) {525FILE *File;526File = getProfileFile();527if (File != NULL) {528return File;529}530531return fopen(OutputName, "ab");532}533534static void closeFileObject(FILE *OutputFile) {535if (OutputFile == getProfileFile()) {536fflush(OutputFile);537if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) {538lprofUnlockFileHandle(OutputFile);539}540} else {541fclose(OutputFile);542}543}544545/* Write profile data to file \c OutputName. */546static int writeFile(const char *OutputName) {547int RetVal;548FILE *OutputFile;549550int MergeDone = 0;551VPMergeHook = &lprofMergeValueProfData;552if (doMerging())553OutputFile = openFileForMerging(OutputName, &MergeDone);554else555OutputFile = getFileObject(OutputName);556557if (!OutputFile)558return -1;559560FreeHook = &free;561setupIOBuffer();562ProfDataWriter fileWriter;563initFileWriter(&fileWriter, OutputFile);564RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);565566closeFileObject(OutputFile);567return RetVal;568}569570#define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE"571572static void truncateCurrentFile(void) {573const char *Filename;574char *FilenameBuf;575FILE *File;576int Length;577578Length = getCurFilenameLength();579FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);580Filename = getCurFilename(FilenameBuf, 0);581if (!Filename)582return;583584/* Only create the profile directory and truncate an existing profile once.585* In continuous mode, this is necessary, as the profile is written-to by the586* runtime initializer. */587int initialized = getenv(LPROF_INIT_ONCE_ENV) != NULL;588if (initialized)589return;590#if defined(_WIN32)591_putenv(LPROF_INIT_ONCE_ENV "=" LPROF_INIT_ONCE_ENV);592#else593setenv(LPROF_INIT_ONCE_ENV, LPROF_INIT_ONCE_ENV, 1);594#endif595596/* Create the profile dir (even if online merging is enabled), so that597* the profile file can be set up if continuous mode is enabled. */598createProfileDir(Filename);599600/* By pass file truncation to allow online raw profile merging. */601if (lprofCurFilename.MergePoolSize)602return;603604/* Truncate the file. Later we'll reopen and append. */605File = fopen(Filename, "w");606if (!File)607return;608fclose(File);609}610611/* Write a partial profile to \p Filename, which is required to be backed by612* the open file object \p File. */613static int writeProfileWithFileObject(const char *Filename, FILE *File) {614setProfileFile(File);615int rc = writeFile(Filename);616if (rc)617PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));618setProfileFile(NULL);619return rc;620}621622static void initializeProfileForContinuousMode(void) {623if (!__llvm_profile_is_continuous_mode_enabled())624return;625if (!ContinuousModeSupported) {626PROF_ERR("%s\n", "continuous mode is unsupported on this platform");627return;628}629if (UseBiasVar && BiasAddr == BiasDefaultAddr &&630BitmapBiasAddr == BitmapBiasDefaultAddr) {631PROF_ERR("%s\n", "Neither __llvm_profile_counter_bias nor "632"__llvm_profile_bitmap_bias is defined");633return;634}635636/* Get the sizes of counter section. */637uint64_t CountersSize = __llvm_profile_get_counters_size(638__llvm_profile_begin_counters(), __llvm_profile_end_counters());639640int Length = getCurFilenameLength();641char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);642const char *Filename = getCurFilename(FilenameBuf, 0);643if (!Filename)644return;645646FILE *File = NULL;647uint64_t CurrentFileOffset = 0;648if (doMerging()) {649/* We are merging profiles. Map the counter section as shared memory into650* the profile, i.e. into each participating process. An increment in one651* process should be visible to every other process with the same counter652* section mapped. */653File = lprofOpenFileEx(Filename);654if (!File)655return;656657uint64_t ProfileFileSize = 0;658if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {659lprofUnlockFileHandle(File);660fclose(File);661return;662}663if (ProfileFileSize == 0) {664/* Grow the profile so that mmap() can succeed. Leak the file handle, as665* the file should stay open. */666if (writeProfileWithFileObject(Filename, File) != 0) {667lprofUnlockFileHandle(File);668fclose(File);669return;670}671} else {672/* The merged profile has a non-zero length. Check that it is compatible673* with the data in this process. */674ManagedMemory ProfileBuffer;675if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {676lprofUnlockFileHandle(File);677fclose(File);678return;679}680(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);681}682} else {683File = fopen(Filename, FileOpenMode);684if (!File)685return;686/* Check that the offset within the file is page-aligned. */687CurrentFileOffset = ftell(File);688unsigned PageSize = getpagesize();689if (CurrentFileOffset % PageSize != 0) {690PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"691"page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n",692(uint64_t)CurrentFileOffset, PageSize);693fclose(File);694return;695}696if (writeProfileWithFileObject(Filename, File) != 0) {697fclose(File);698return;699}700}701702/* mmap() the profile counters so long as there is at least one counter.703* If there aren't any counters, mmap() would fail with EINVAL. */704if (CountersSize > 0)705mmapForContinuousMode(CurrentFileOffset, File);706707if (doMerging()) {708lprofUnlockFileHandle(File);709}710if (File != NULL) {711fclose(File);712}713}714715static const char *DefaultProfileName = "default.profraw";716static void resetFilenameToDefault(void) {717if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {718#ifdef __GNUC__719#pragma GCC diagnostic push720#pragma GCC diagnostic ignored "-Wcast-qual"721#elif defined(__clang__)722#pragma clang diagnostic push723#pragma clang diagnostic ignored "-Wcast-qual"724#endif725free((void *)lprofCurFilename.FilenamePat);726#ifdef __GNUC__727#pragma GCC diagnostic pop728#elif defined(__clang__)729#pragma clang diagnostic pop730#endif731}732memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));733lprofCurFilename.FilenamePat = DefaultProfileName;734lprofCurFilename.PNS = PNS_default;735}736737static unsigned getMergePoolSize(const char *FilenamePat, int *I) {738unsigned J = 0, Num = 0;739for (;; ++J) {740char C = FilenamePat[*I + J];741if (C == 'm') {742*I += J;743return Num ? Num : 1;744}745if (C < '0' || C > '9')746break;747Num = Num * 10 + C - '0';748749/* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed750* to be in-bound as the string is null terminated. */751}752return 0;753}754755/* Assert that Idx does index past a string null terminator. Return the756* result of the check. */757static int checkBounds(int Idx, int Strlen) {758assert(Idx <= Strlen && "Indexing past string null terminator");759return Idx <= Strlen;760}761762/* Parses the pattern string \p FilenamePat and stores the result to763* lprofcurFilename structure. */764static int parseFilenamePattern(const char *FilenamePat,765unsigned CopyFilenamePat) {766int NumPids = 0, NumHosts = 0, NumBinaryIds = 0, I;767char *PidChars = &lprofCurFilename.PidChars[0];768char *Hostname = &lprofCurFilename.Hostname[0];769int MergingEnabled = 0;770int FilenamePatLen = strlen(FilenamePat);771772#ifdef __GNUC__773#pragma GCC diagnostic push774#pragma GCC diagnostic ignored "-Wcast-qual"775#elif defined(__clang__)776#pragma clang diagnostic push777#pragma clang diagnostic ignored "-Wcast-qual"778#endif779/* Clean up cached prefix and filename. */780if (lprofCurFilename.ProfilePathPrefix)781free((void *)lprofCurFilename.ProfilePathPrefix);782783if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {784free((void *)lprofCurFilename.FilenamePat);785}786#ifdef __GNUC__787#pragma GCC diagnostic pop788#elif defined(__clang__)789#pragma clang diagnostic pop790#endif791792memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));793794if (!CopyFilenamePat)795lprofCurFilename.FilenamePat = FilenamePat;796else {797lprofCurFilename.FilenamePat = strdup(FilenamePat);798lprofCurFilename.OwnsFilenamePat = 1;799}800/* Check the filename for "%p", which indicates a pid-substitution. */801for (I = 0; checkBounds(I, FilenamePatLen) && FilenamePat[I]; ++I) {802if (FilenamePat[I] == '%') {803++I; /* Advance to the next character. */804if (!checkBounds(I, FilenamePatLen))805break;806if (FilenamePat[I] == 'p') {807if (!NumPids++) {808if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {809PROF_WARN("Unable to get pid for filename pattern %s. Using the "810"default name.",811FilenamePat);812return -1;813}814}815} else if (FilenamePat[I] == 'h') {816if (!NumHosts++)817if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {818PROF_WARN("Unable to get hostname for filename pattern %s. Using "819"the default name.",820FilenamePat);821return -1;822}823} else if (FilenamePat[I] == 't') {824lprofCurFilename.TmpDir = getenv("TMPDIR");825if (!lprofCurFilename.TmpDir) {826PROF_WARN("Unable to get the TMPDIR environment variable, referenced "827"in %s. Using the default path.",828FilenamePat);829return -1;830}831} else if (FilenamePat[I] == 'b') {832if (!NumBinaryIds++) {833/* Check if binary ID does not exist or if its size is 0. */834if (__llvm_write_binary_ids(NULL) <= 0) {835PROF_WARN("Unable to get binary ID for filename pattern %s. Using "836"the default name.",837FilenamePat);838return -1;839}840}841} else if (FilenamePat[I] == 'c') {842if (__llvm_profile_is_continuous_mode_enabled()) {843PROF_WARN("%%c specifier can only be specified once in %s.\n",844FilenamePat);845__llvm_profile_disable_continuous_mode();846return -1;847}848#if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32) || defined(_AIX)849__llvm_profile_set_page_size(getpagesize());850__llvm_profile_enable_continuous_mode();851#else852PROF_WARN("%s",853"Continuous mode is currently only supported for Mach-O,"854" ELF and COFF formats.");855return -1;856#endif857} else {858unsigned MergePoolSize = getMergePoolSize(FilenamePat, &I);859if (!MergePoolSize)860continue;861if (MergingEnabled) {862PROF_WARN("%%m specifier can only be specified once in %s.\n",863FilenamePat);864return -1;865}866MergingEnabled = 1;867lprofCurFilename.MergePoolSize = MergePoolSize;868}869}870}871872lprofCurFilename.NumPids = NumPids;873lprofCurFilename.NumHosts = NumHosts;874lprofCurFilename.NumBinaryIds = NumBinaryIds;875return 0;876}877878static void parseAndSetFilename(const char *FilenamePat,879ProfileNameSpecifier PNS,880unsigned CopyFilenamePat) {881882const char *OldFilenamePat = lprofCurFilename.FilenamePat;883ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;884885/* The old profile name specifier takes precedence over the old one. */886if (PNS < OldPNS)887return;888889if (!FilenamePat)890FilenamePat = DefaultProfileName;891892if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {893lprofCurFilename.PNS = PNS;894return;895}896897/* When PNS >= OldPNS, the last one wins. */898if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))899resetFilenameToDefault();900lprofCurFilename.PNS = PNS;901902if (!OldFilenamePat) {903if (getenv("LLVM_PROFILE_VERBOSE"))904PROF_NOTE("Set profile file path to \"%s\" via %s.\n",905lprofCurFilename.FilenamePat, getPNSStr(PNS));906} else {907if (getenv("LLVM_PROFILE_VERBOSE"))908PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",909OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,910getPNSStr(PNS));911}912913truncateCurrentFile();914if (__llvm_profile_is_continuous_mode_enabled())915initializeProfileForContinuousMode();916}917918/* Return buffer length that is required to store the current profile919* filename with PID and hostname substitutions. */920/* The length to hold uint64_t followed by 3 digits pool id including '_' */921#define SIGLEN 24922/* The length to hold 160-bit hash in hexadecimal form */923#define BINARY_ID_LEN 40924static int getCurFilenameLength(void) {925int Len;926if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])927return 0;928929if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||930lprofCurFilename.NumBinaryIds || lprofCurFilename.TmpDir ||931lprofCurFilename.MergePoolSize))932return strlen(lprofCurFilename.FilenamePat);933934Len = strlen(lprofCurFilename.FilenamePat) +935lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +936lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) +937lprofCurFilename.NumBinaryIds * BINARY_ID_LEN +938(lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0);939if (lprofCurFilename.MergePoolSize)940Len += SIGLEN;941return Len;942}943944typedef struct lprofBinaryIdsBuffer {945char String[BINARY_ID_LEN + 1];946int Length;947} lprofBinaryIdsBuffer;948949/* Reads binary ID length and then its data, writes it into lprofBinaryIdsBuffer950* in hexadecimal form. */951static uint32_t binaryIdsStringWriter(ProfDataWriter *This,952ProfDataIOVec *IOVecs,953uint32_t NumIOVecs) {954if (NumIOVecs < 2 || IOVecs[0].ElmSize != sizeof(uint64_t))955return -1;956uint64_t BinaryIdLen = *(const uint64_t *)IOVecs[0].Data;957if (IOVecs[1].ElmSize != sizeof(uint8_t) || IOVecs[1].NumElm != BinaryIdLen)958return -1;959const uint8_t *BinaryIdData = (const uint8_t *)IOVecs[1].Data;960lprofBinaryIdsBuffer *Data = (lprofBinaryIdsBuffer *)This->WriterCtx;961for (uint64_t I = 0; I < BinaryIdLen; I++) {962Data->Length +=963snprintf(Data->String + Data->Length, BINARY_ID_LEN + 1 - Data->Length,964"%02hhx", BinaryIdData[I]);965}966return 0;967}968969/* Return the pointer to the current profile file name (after substituting970* PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer971* to store the resulting filename. If no substitution is needed, the972* current filename pattern string is directly returned, unless ForceUseBuf973* is enabled. */974static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {975int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength;976const char *FilenamePat = lprofCurFilename.FilenamePat;977978if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])979return 0;980981if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||982lprofCurFilename.NumBinaryIds || lprofCurFilename.TmpDir ||983lprofCurFilename.MergePoolSize ||984__llvm_profile_is_continuous_mode_enabled())) {985if (!ForceUseBuf)986return lprofCurFilename.FilenamePat;987988FilenamePatLength = strlen(lprofCurFilename.FilenamePat);989memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);990FilenameBuf[FilenamePatLength] = '\0';991return FilenameBuf;992}993994PidLength = strlen(lprofCurFilename.PidChars);995HostNameLength = strlen(lprofCurFilename.Hostname);996TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0;997/* Construct the new filename. */998for (I = 0, J = 0; FilenamePat[I]; ++I)999if (FilenamePat[I] == '%') {1000if (FilenamePat[++I] == 'p') {1001memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);1002J += PidLength;1003} else if (FilenamePat[I] == 'h') {1004memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);1005J += HostNameLength;1006} else if (FilenamePat[I] == 't') {1007memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength);1008FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR;1009J += TmpDirLength + 1;1010} else if (FilenamePat[I] == 'b') {1011lprofBinaryIdsBuffer Data = {{0}, 0};1012ProfDataWriter Writer = {binaryIdsStringWriter, &Data};1013__llvm_write_binary_ids(&Writer);1014memcpy(FilenameBuf + J, Data.String, Data.Length);1015J += Data.Length;1016} else {1017if (!getMergePoolSize(FilenamePat, &I))1018continue;1019char LoadModuleSignature[SIGLEN + 1];1020int S;1021int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;1022S = snprintf(LoadModuleSignature, SIGLEN + 1, "%" PRIu64 "_%d",1023lprofGetLoadModuleSignature(), ProfilePoolId);1024if (S == -1 || S > SIGLEN)1025S = SIGLEN;1026memcpy(FilenameBuf + J, LoadModuleSignature, S);1027J += S;1028}1029/* Drop any unknown substitutions. */1030} else1031FilenameBuf[J++] = FilenamePat[I];1032FilenameBuf[J] = 0;10331034return FilenameBuf;1035}10361037/* Returns the pointer to the environment variable1038* string. Returns null if the env var is not set. */1039static const char *getFilenamePatFromEnv(void) {1040const char *Filename = getenv("LLVM_PROFILE_FILE");1041if (!Filename || !Filename[0])1042return 0;1043return Filename;1044}10451046COMPILER_RT_VISIBILITY1047const char *__llvm_profile_get_path_prefix(void) {1048int Length;1049char *FilenameBuf, *Prefix;1050const char *Filename, *PrefixEnd;10511052if (lprofCurFilename.ProfilePathPrefix)1053return lprofCurFilename.ProfilePathPrefix;10541055Length = getCurFilenameLength();1056FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);1057Filename = getCurFilename(FilenameBuf, 0);1058if (!Filename)1059return "\0";10601061PrefixEnd = lprofFindLastDirSeparator(Filename);1062if (!PrefixEnd)1063return "\0";10641065Length = PrefixEnd - Filename + 1;1066Prefix = (char *)malloc(Length + 1);1067if (!Prefix) {1068PROF_ERR("Failed to %s\n", "allocate memory.");1069return "\0";1070}1071memcpy(Prefix, Filename, Length);1072Prefix[Length] = '\0';1073lprofCurFilename.ProfilePathPrefix = Prefix;1074return Prefix;1075}10761077COMPILER_RT_VISIBILITY1078const char *__llvm_profile_get_filename(void) {1079int Length;1080char *FilenameBuf;1081const char *Filename;10821083Length = getCurFilenameLength();1084FilenameBuf = (char *)malloc(Length + 1);1085if (!FilenameBuf) {1086PROF_ERR("Failed to %s\n", "allocate memory.");1087return "\0";1088}1089Filename = getCurFilename(FilenameBuf, 1);1090if (!Filename) {1091free(FilenameBuf);1092return "\0";1093}10941095return FilenameBuf;1096}10971098/* This API initializes the file handling, both user specified1099* profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE1100* environment variable can override this default value.1101*/1102COMPILER_RT_VISIBILITY1103void __llvm_profile_initialize_file(void) {1104const char *EnvFilenamePat;1105const char *SelectedPat = NULL;1106ProfileNameSpecifier PNS = PNS_unknown;1107int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);11081109EnvFilenamePat = getFilenamePatFromEnv();1110if (EnvFilenamePat) {1111/* Pass CopyFilenamePat = 1, to ensure that the filename would be valid1112at the moment when __llvm_profile_write_file() gets executed. */1113parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);1114return;1115} else if (hasCommandLineOverrider) {1116SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;1117PNS = PNS_command_line;1118} else {1119SelectedPat = NULL;1120PNS = PNS_default;1121}11221123parseAndSetFilename(SelectedPat, PNS, 0);1124}11251126/* This method is invoked by the runtime initialization hook1127* InstrProfilingRuntime.o if it is linked in.1128*/1129COMPILER_RT_VISIBILITY1130void __llvm_profile_initialize(void) {1131__llvm_profile_initialize_file();1132if (!__llvm_profile_is_continuous_mode_enabled())1133__llvm_profile_register_write_file_atexit();1134}11351136/* This API is directly called by the user application code. It has the1137* highest precedence compared with LLVM_PROFILE_FILE environment variable1138* and command line option -fprofile-instr-generate=<profile_name>.1139*/1140COMPILER_RT_VISIBILITY1141void __llvm_profile_set_filename(const char *FilenamePat) {1142if (__llvm_profile_is_continuous_mode_enabled())1143return;1144parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);1145}11461147/* The public API for writing profile data into the file with name1148* set by previous calls to __llvm_profile_set_filename or1149* __llvm_profile_override_default_filename or1150* __llvm_profile_initialize_file. */1151COMPILER_RT_VISIBILITY1152int __llvm_profile_write_file(void) {1153int rc, Length;1154const char *Filename;1155char *FilenameBuf;11561157// Temporarily suspend getting SIGKILL when the parent exits.1158int PDeathSig = lprofSuspendSigKill();11591160if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {1161PROF_NOTE("Profile data not written to file: %s.\n", "already written");1162if (PDeathSig == 1)1163lprofRestoreSigKill();1164return 0;1165}11661167Length = getCurFilenameLength();1168FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);1169Filename = getCurFilename(FilenameBuf, 0);11701171/* Check the filename. */1172if (!Filename) {1173PROF_ERR("Failed to write file : %s\n", "Filename not set");1174if (PDeathSig == 1)1175lprofRestoreSigKill();1176return -1;1177}11781179/* Check if there is llvm/runtime version mismatch. */1180if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {1181PROF_ERR("Runtime and instrumentation version mismatch : "1182"expected %d, but get %d\n",1183INSTR_PROF_RAW_VERSION,1184(int)GET_VERSION(__llvm_profile_get_version()));1185if (PDeathSig == 1)1186lprofRestoreSigKill();1187return -1;1188}11891190/* Write profile data to the file. */1191rc = writeFile(Filename);1192if (rc)1193PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));11941195// Restore SIGKILL.1196if (PDeathSig == 1)1197lprofRestoreSigKill();11981199return rc;1200}12011202COMPILER_RT_VISIBILITY1203int __llvm_profile_dump(void) {1204if (!doMerging())1205PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "1206" of previously dumped profile data : %s. Either use %%m "1207"in profile name or change profile name before dumping.\n",1208"online profile merging is not on");1209int rc = __llvm_profile_write_file();1210lprofSetProfileDumped(1);1211return rc;1212}12131214static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }12151216COMPILER_RT_VISIBILITY1217int __llvm_profile_register_write_file_atexit(void) {1218static int HasBeenRegistered = 0;12191220if (HasBeenRegistered)1221return 0;12221223lprofSetupValueProfiler();12241225HasBeenRegistered = 1;1226return lprofAtExit(writeFileWithoutReturn);1227}12281229COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,1230int EnableMerge) {1231if (__llvm_profile_is_continuous_mode_enabled()) {1232if (!EnableMerge) {1233PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "1234"continuous sync mode when merging is disabled\n",1235fileno(File));1236return 1;1237}1238if (lprofLockFileHandle(File) != 0) {1239PROF_WARN("Data may be corrupted during profile merging : %s\n",1240"Fail to obtain file lock due to system limit.");1241}1242uint64_t ProfileFileSize = 0;1243if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {1244lprofUnlockFileHandle(File);1245return 1;1246}1247if (ProfileFileSize == 0) {1248FreeHook = &free;1249setupIOBuffer();1250ProfDataWriter fileWriter;1251initFileWriter(&fileWriter, File);1252if (lprofWriteData(&fileWriter, 0, 0)) {1253lprofUnlockFileHandle(File);1254PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File),1255strerror(errno));1256return 1;1257}1258fflush(File);1259} else {1260/* The merged profile has a non-zero length. Check that it is compatible1261* with the data in this process. */1262ManagedMemory ProfileBuffer;1263if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {1264lprofUnlockFileHandle(File);1265return 1;1266}1267(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);1268}1269mmapForContinuousMode(0, File);1270lprofUnlockFileHandle(File);1271} else {1272setProfileFile(File);1273setProfileMergeRequested(EnableMerge);1274}1275return 0;1276}12771278#ifndef __APPLE__1279int __llvm_write_custom_profile(const char *Target,1280const __llvm_profile_data *DataBegin,1281const __llvm_profile_data *DataEnd,1282const char *CountersBegin,1283const char *CountersEnd, const char *NamesBegin,1284const char *NamesEnd,1285const uint64_t *VersionOverride) {1286int ReturnValue = 0, FilenameLength, TargetLength;1287char *FilenameBuf, *TargetFilename;1288const char *Filename;12891290/* Save old profile data */1291FILE *oldFile = getProfileFile();12921293// Temporarily suspend getting SIGKILL when the parent exits.1294int PDeathSig = lprofSuspendSigKill();12951296if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {1297PROF_NOTE("Profile data not written to file: %s.\n", "already written");1298if (PDeathSig == 1)1299lprofRestoreSigKill();1300return 0;1301}13021303/* Check if there is llvm/runtime version mismatch. */1304if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {1305PROF_ERR("Runtime and instrumentation version mismatch : "1306"expected %d, but get %d\n",1307INSTR_PROF_RAW_VERSION,1308(int)GET_VERSION(__llvm_profile_get_version()));1309if (PDeathSig == 1)1310lprofRestoreSigKill();1311return -1;1312}13131314/* Get current filename */1315FilenameLength = getCurFilenameLength();1316FilenameBuf = (char *)COMPILER_RT_ALLOCA(FilenameLength + 1);1317Filename = getCurFilename(FilenameBuf, 0);13181319/* Check the filename. */1320if (!Filename) {1321PROF_ERR("Failed to write file : %s\n", "Filename not set");1322if (PDeathSig == 1)1323lprofRestoreSigKill();1324return -1;1325}13261327/* Allocate new space for our target-specific PGO filename */1328TargetLength = strlen(Target);1329TargetFilename =1330(char *)COMPILER_RT_ALLOCA(FilenameLength + TargetLength + 2);13311332/* Find file basename and path sizes */1333int32_t DirEnd = FilenameLength - 1;1334while (DirEnd >= 0 && !IS_DIR_SEPARATOR(Filename[DirEnd])) {1335DirEnd--;1336}1337uint32_t DirSize = DirEnd + 1, BaseSize = FilenameLength - DirSize;13381339/* Prepend "TARGET." to current filename */1340if (DirSize > 0) {1341memcpy(TargetFilename, Filename, DirSize);1342}1343memcpy(TargetFilename + DirSize, Target, TargetLength);1344TargetFilename[TargetLength + DirSize] = '.';1345memcpy(TargetFilename + DirSize + 1 + TargetLength, Filename + DirSize,1346BaseSize);1347TargetFilename[FilenameLength + 1 + TargetLength] = 0;13481349/* Open and truncate target-specific PGO file */1350FILE *OutputFile = fopen(TargetFilename, "w");1351setProfileFile(OutputFile);13521353if (!OutputFile) {1354PROF_ERR("Failed to open file : %s\n", TargetFilename);1355if (PDeathSig == 1)1356lprofRestoreSigKill();1357return -1;1358}13591360FreeHook = &free;1361setupIOBuffer();13621363/* Write custom data */1364ProfDataWriter fileWriter;1365initFileWriter(&fileWriter, OutputFile);13661367uint64_t Version = __llvm_profile_get_version();1368if (VersionOverride)1369Version = *VersionOverride;13701371/* Write custom data to the file */1372ReturnValue =1373lprofWriteDataImpl(&fileWriter, DataBegin, DataEnd, CountersBegin,1374CountersEnd, NULL, NULL, lprofGetVPDataReader(), NULL,1375NULL, NULL, NULL, NamesBegin, NamesEnd, 0, Version);1376closeFileObject(OutputFile);13771378// Restore SIGKILL.1379if (PDeathSig == 1)1380lprofRestoreSigKill();13811382/* Restore old profiling file */1383setProfileFile(oldFile);13841385return ReturnValue;1386}1387#endif13881389#endif139013911392