1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
2 |*
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 |* See https://llvm.org/LICENSE.txt for license information.
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 |*
7 \*===----------------------------------------------------------------------===*/
8 
9 #if !defined(__Fuchsia__)
10 
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #ifdef _MSC_VER
16 /* For _alloca. */
17 #include <malloc.h>
18 #endif
19 #if defined(_WIN32)
20 #include "WindowsMMap.h"
21 /* For _chsize_s */
22 #include <io.h>
23 #include <process.h>
24 #else
25 #include <sys/file.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28 #if defined(__linux__)
29 #include <sys/types.h>
30 #endif
31 #endif
32 
33 #include "InstrProfiling.h"
34 #include "InstrProfilingInternal.h"
35 #include "InstrProfilingUtil.h"
36 
37 /* From where is profile name specified.
38  * The order the enumerators define their
39  * precedence. Re-order them may lead to
40  * runtime behavior change. */
41 typedef enum ProfileNameSpecifier {
42   PNS_unknown = 0,
43   PNS_default,
44   PNS_command_line,
45   PNS_environment,
46   PNS_runtime_api
47 } ProfileNameSpecifier;
48 
49 static const char *getPNSStr(ProfileNameSpecifier PNS) {
50   switch (PNS) {
51   case PNS_default:
52     return "default setting";
53   case PNS_command_line:
54     return "command line";
55   case PNS_environment:
56     return "environment variable";
57   case PNS_runtime_api:
58     return "runtime API";
59   default:
60     return "Unknown";
61   }
62 }
63 
64 #define MAX_PID_SIZE 16
65 /* Data structure holding the result of parsed filename pattern. */
66 typedef struct lprofFilename {
67   /* File name string possibly with %p or %h specifiers. */
68   const char *FilenamePat;
69   /* A flag indicating if FilenamePat's memory is allocated
70    * by runtime. */
71   unsigned OwnsFilenamePat;
72   const char *ProfilePathPrefix;
73   const char *Filename;
74   char PidChars[MAX_PID_SIZE];
75   char Hostname[COMPILER_RT_MAX_HOSTLEN];
76   unsigned NumPids;
77   unsigned NumHosts;
78   /* When in-process merging is enabled, this parameter specifies
79    * the total number of profile data files shared by all the processes
80    * spawned from the same binary. By default the value is 1. If merging
81    * is not enabled, its value should be 0. This parameter is specified
82    * by the %[0-9]m specifier. For instance %2m enables merging using
83    * 2 profile data files. %1m is equivalent to %m. Also %m specifier
84    * can only appear once at the end of the name pattern. */
85   unsigned MergePoolSize;
86   ProfileNameSpecifier PNS;
87 } lprofFilename;
88 
89 COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0,   0, 0, 0, {0},
90                                                    {0}, 0, 0, 0, PNS_unknown};
91 
92 static int getCurFilenameLength();
93 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
94 static unsigned doMerging() { return lprofCurFilename.MergePoolSize; }
95 
96 /* Return 1 if there is an error, otherwise return  0.  */
97 static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
98                            uint32_t NumIOVecs) {
99   uint32_t I;
100   FILE *File = (FILE *)This->WriterCtx;
101   for (I = 0; I < NumIOVecs; I++) {
102     if (IOVecs[I].Data) {
103       if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
104           IOVecs[I].NumElm)
105         return 1;
106     } else {
107       if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
108         return 1;
109     }
110   }
111   return 0;
112 }
113 
114 /* TODO: make buffer size controllable by an internal option, and compiler can pass the size
115    to runtime via a variable. */
116 static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) {
117   if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) !=
118       INSTR_ORDER_FILE_BUFFER_SIZE)
119     return 1;
120   return 0;
121 }
122 
123 static void initFileWriter(ProfDataWriter *This, FILE *File) {
124   This->Write = fileWriter;
125   This->WriterCtx = File;
126 }
127 
128 COMPILER_RT_VISIBILITY ProfBufferIO *
129 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
130   FreeHook = &free;
131   DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
132   VPBufferSize = BufferSz;
133   ProfDataWriter *fileWriter =
134       (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1);
135   initFileWriter(fileWriter, File);
136   ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
137   IO->OwnFileWriter = 1;
138   return IO;
139 }
140 
141 static void setupIOBuffer() {
142   const char *BufferSzStr = 0;
143   BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
144   if (BufferSzStr && BufferSzStr[0]) {
145     VPBufferSize = atoi(BufferSzStr);
146     DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
147   }
148 }
149 
150 /* Read profile data in \c ProfileFile and merge with in-memory
151    profile counters. Returns -1 if there is fatal error, otheriwse
152    0 is returned. Returning 0 does not mean merge is actually
153    performed. If merge is actually done, *MergeDone is set to 1.
154 */
155 static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
156   uint64_t ProfileFileSize;
157   char *ProfileBuffer;
158 
159   if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
160     PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
161              strerror(errno));
162     return -1;
163   }
164   ProfileFileSize = ftell(ProfileFile);
165 
166   /* Restore file offset.  */
167   if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
168     PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
169              strerror(errno));
170     return -1;
171   }
172 
173   /* Nothing to merge.  */
174   if (ProfileFileSize < sizeof(__llvm_profile_header)) {
175     if (ProfileFileSize)
176       PROF_WARN("Unable to merge profile data: %s\n",
177                 "source profile file is too small.");
178     return 0;
179   }
180 
181   ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
182                        fileno(ProfileFile), 0);
183   if (ProfileBuffer == MAP_FAILED) {
184     PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
185              strerror(errno));
186     return -1;
187   }
188 
189   if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
190     (void)munmap(ProfileBuffer, ProfileFileSize);
191     PROF_WARN("Unable to merge profile data: %s\n",
192               "source profile file is not compatible.");
193     return 0;
194   }
195 
196   /* Now start merging */
197   __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
198 
199   // Truncate the file in case merging of value profile did not happend to
200   // prevent from leaving garbage data at the end of the profile file.
201   COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer());
202 
203   (void)munmap(ProfileBuffer, ProfileFileSize);
204   *MergeDone = 1;
205 
206   return 0;
207 }
208 
209 /* Create the directory holding the file, if needed. */
210 static void createProfileDir(const char *Filename) {
211   size_t Length = strlen(Filename);
212   if (lprofFindFirstDirSeparator(Filename)) {
213     char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
214     strncpy(Copy, Filename, Length + 1);
215     __llvm_profile_recursive_mkdir(Copy);
216   }
217 }
218 
219 /* Open the profile data for merging. It opens the file in r+b mode with
220  * file locking.  If the file has content which is compatible with the
221  * current process, it also reads in the profile data in the file and merge
222  * it with in-memory counters. After the profile data is merged in memory,
223  * the original profile data is truncated and gets ready for the profile
224  * dumper. With profile merging enabled, each executable as well as any of
225  * its instrumented shared libraries dump profile data into their own data file.
226 */
227 static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
228   FILE *ProfileFile;
229   int rc;
230 
231   createProfileDir(ProfileFileName);
232   ProfileFile = lprofOpenFileEx(ProfileFileName);
233   if (!ProfileFile)
234     return NULL;
235 
236   rc = doProfileMerging(ProfileFile, MergeDone);
237   if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
238       fseek(ProfileFile, 0L, SEEK_SET) == -1) {
239     PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
240              strerror(errno));
241     fclose(ProfileFile);
242     return NULL;
243   }
244   return ProfileFile;
245 }
246 
247 /* Write profile data to file \c OutputName.  */
248 static int writeFile(const char *OutputName) {
249   int RetVal;
250   FILE *OutputFile;
251 
252   int MergeDone = 0;
253   VPMergeHook = &lprofMergeValueProfData;
254   if (!doMerging())
255     OutputFile = fopen(OutputName, "ab");
256   else
257     OutputFile = openFileForMerging(OutputName, &MergeDone);
258 
259   if (!OutputFile)
260     return -1;
261 
262   FreeHook = &free;
263   setupIOBuffer();
264   ProfDataWriter fileWriter;
265   initFileWriter(&fileWriter, OutputFile);
266   RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
267 
268   fclose(OutputFile);
269   return RetVal;
270 }
271 
272 /* Write order data to file \c OutputName.  */
273 static int writeOrderFile(const char *OutputName) {
274   int RetVal;
275   FILE *OutputFile;
276 
277   OutputFile = fopen(OutputName, "w");
278 
279   if (!OutputFile) {
280     PROF_WARN("can't open file with mode ab: %s\n", OutputName);
281     return -1;
282   }
283 
284   FreeHook = &free;
285   setupIOBuffer();
286   const uint32_t *DataBegin = __llvm_profile_begin_orderfile();
287   RetVal = orderFileWriter(OutputFile, DataBegin);
288 
289   fclose(OutputFile);
290   return RetVal;
291 }
292 
293 static void truncateCurrentFile(void) {
294   const char *Filename;
295   char *FilenameBuf;
296   FILE *File;
297   int Length;
298 
299   Length = getCurFilenameLength();
300   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
301   Filename = getCurFilename(FilenameBuf, 0);
302   if (!Filename)
303     return;
304 
305   /* By pass file truncation to allow online raw profile
306    * merging. */
307   if (lprofCurFilename.MergePoolSize)
308     return;
309 
310   createProfileDir(Filename);
311 
312   /* Truncate the file.  Later we'll reopen and append. */
313   File = fopen(Filename, "w");
314   if (!File)
315     return;
316   fclose(File);
317 }
318 
319 static const char *DefaultProfileName = "default.profraw";
320 static void resetFilenameToDefault(void) {
321   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
322     free((void *)lprofCurFilename.FilenamePat);
323   }
324   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
325   lprofCurFilename.FilenamePat = DefaultProfileName;
326   lprofCurFilename.PNS = PNS_default;
327 }
328 
329 static int containsMergeSpecifier(const char *FilenamePat, int I) {
330   return (FilenamePat[I] == 'm' ||
331           (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
332            /* If FilenamePat[I] is not '\0', the next byte is guaranteed
333             * to be in-bound as the string is null terminated. */
334            FilenamePat[I + 1] == 'm'));
335 }
336 
337 /* Parses the pattern string \p FilenamePat and stores the result to
338  * lprofcurFilename structure. */
339 static int parseFilenamePattern(const char *FilenamePat,
340                                 unsigned CopyFilenamePat) {
341   int NumPids = 0, NumHosts = 0, I;
342   char *PidChars = &lprofCurFilename.PidChars[0];
343   char *Hostname = &lprofCurFilename.Hostname[0];
344   int MergingEnabled = 0;
345 
346   /* Clean up cached prefix and filename.  */
347   if (lprofCurFilename.ProfilePathPrefix)
348     free((void *)lprofCurFilename.ProfilePathPrefix);
349   if (lprofCurFilename.Filename)
350     free((void *)lprofCurFilename.Filename);
351 
352   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
353     free((void *)lprofCurFilename.FilenamePat);
354   }
355 
356   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
357 
358   if (!CopyFilenamePat)
359     lprofCurFilename.FilenamePat = FilenamePat;
360   else {
361     lprofCurFilename.FilenamePat = strdup(FilenamePat);
362     lprofCurFilename.OwnsFilenamePat = 1;
363   }
364   /* Check the filename for "%p", which indicates a pid-substitution. */
365   for (I = 0; FilenamePat[I]; ++I)
366     if (FilenamePat[I] == '%') {
367       if (FilenamePat[++I] == 'p') {
368         if (!NumPids++) {
369           if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
370             PROF_WARN("Unable to get pid for filename pattern %s. Using the "
371                       "default name.",
372                       FilenamePat);
373             return -1;
374           }
375         }
376       } else if (FilenamePat[I] == 'h') {
377         if (!NumHosts++)
378           if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
379             PROF_WARN("Unable to get hostname for filename pattern %s. Using "
380                       "the default name.",
381                       FilenamePat);
382             return -1;
383           }
384       } else if (containsMergeSpecifier(FilenamePat, I)) {
385         if (MergingEnabled) {
386           PROF_WARN("%%m specifier can only be specified once in %s.\n",
387                     FilenamePat);
388           return -1;
389         }
390         MergingEnabled = 1;
391         if (FilenamePat[I] == 'm')
392           lprofCurFilename.MergePoolSize = 1;
393         else {
394           lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
395           I++; /* advance to 'm' */
396         }
397       }
398     }
399 
400   lprofCurFilename.NumPids = NumPids;
401   lprofCurFilename.NumHosts = NumHosts;
402   return 0;
403 }
404 
405 static void parseAndSetFilename(const char *FilenamePat,
406                                 ProfileNameSpecifier PNS,
407                                 unsigned CopyFilenamePat) {
408 
409   const char *OldFilenamePat = lprofCurFilename.FilenamePat;
410   ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
411 
412   if (PNS < OldPNS)
413     return;
414 
415   if (!FilenamePat)
416     FilenamePat = DefaultProfileName;
417 
418   if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
419     lprofCurFilename.PNS = PNS;
420     return;
421   }
422 
423   /* When PNS >= OldPNS, the last one wins. */
424   if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
425     resetFilenameToDefault();
426   lprofCurFilename.PNS = PNS;
427 
428   if (!OldFilenamePat) {
429     if (getenv("LLVM_PROFILE_VERBOSE"))
430       PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
431                 lprofCurFilename.FilenamePat, getPNSStr(PNS));
432   } else {
433     if (getenv("LLVM_PROFILE_VERBOSE"))
434       PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
435                 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
436                 getPNSStr(PNS));
437   }
438 
439   truncateCurrentFile();
440 }
441 
442 /* Return buffer length that is required to store the current profile
443  * filename with PID and hostname substitutions. */
444 /* The length to hold uint64_t followed by 2 digit pool id including '_' */
445 #define SIGLEN 24
446 static int getCurFilenameLength() {
447   int Len;
448   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
449     return 0;
450 
451   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
452         lprofCurFilename.MergePoolSize))
453     return strlen(lprofCurFilename.FilenamePat);
454 
455   Len = strlen(lprofCurFilename.FilenamePat) +
456         lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
457         lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
458   if (lprofCurFilename.MergePoolSize)
459     Len += SIGLEN;
460   return Len;
461 }
462 
463 /* Return the pointer to the current profile file name (after substituting
464  * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
465  * to store the resulting filename. If no substitution is needed, the
466  * current filename pattern string is directly returned, unless ForceUseBuf
467  * is enabled. */
468 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
469   int I, J, PidLength, HostNameLength, FilenamePatLength;
470   const char *FilenamePat = lprofCurFilename.FilenamePat;
471 
472   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
473     return 0;
474 
475   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
476         lprofCurFilename.MergePoolSize)) {
477     if (!ForceUseBuf)
478       return lprofCurFilename.FilenamePat;
479 
480     FilenamePatLength = strlen(lprofCurFilename.FilenamePat);
481     memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);
482     FilenameBuf[FilenamePatLength] = '\0';
483     return FilenameBuf;
484   }
485 
486   PidLength = strlen(lprofCurFilename.PidChars);
487   HostNameLength = strlen(lprofCurFilename.Hostname);
488   /* Construct the new filename. */
489   for (I = 0, J = 0; FilenamePat[I]; ++I)
490     if (FilenamePat[I] == '%') {
491       if (FilenamePat[++I] == 'p') {
492         memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
493         J += PidLength;
494       } else if (FilenamePat[I] == 'h') {
495         memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
496         J += HostNameLength;
497       } else if (containsMergeSpecifier(FilenamePat, I)) {
498         char LoadModuleSignature[SIGLEN];
499         int S;
500         int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
501         S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d",
502                      lprofGetLoadModuleSignature(), ProfilePoolId);
503         if (S == -1 || S > SIGLEN)
504           S = SIGLEN;
505         memcpy(FilenameBuf + J, LoadModuleSignature, S);
506         J += S;
507         if (FilenamePat[I] != 'm')
508           I++;
509       }
510       /* Drop any unknown substitutions. */
511     } else
512       FilenameBuf[J++] = FilenamePat[I];
513   FilenameBuf[J] = 0;
514 
515   return FilenameBuf;
516 }
517 
518 /* Returns the pointer to the environment variable
519  * string. Returns null if the env var is not set. */
520 static const char *getFilenamePatFromEnv(void) {
521   const char *Filename = getenv("LLVM_PROFILE_FILE");
522   if (!Filename || !Filename[0])
523     return 0;
524   return Filename;
525 }
526 
527 COMPILER_RT_VISIBILITY
528 const char *__llvm_profile_get_path_prefix(void) {
529   int Length;
530   char *FilenameBuf, *Prefix;
531   const char *Filename, *PrefixEnd;
532 
533   if (lprofCurFilename.ProfilePathPrefix)
534     return lprofCurFilename.ProfilePathPrefix;
535 
536   Length = getCurFilenameLength();
537   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
538   Filename = getCurFilename(FilenameBuf, 0);
539   if (!Filename)
540     return "\0";
541 
542   PrefixEnd = lprofFindLastDirSeparator(Filename);
543   if (!PrefixEnd)
544     return "\0";
545 
546   Length = PrefixEnd - Filename + 1;
547   Prefix = (char *)malloc(Length + 1);
548   if (!Prefix) {
549     PROF_ERR("Failed to %s\n", "allocate memory.");
550     return "\0";
551   }
552   memcpy(Prefix, Filename, Length);
553   Prefix[Length] = '\0';
554   lprofCurFilename.ProfilePathPrefix = Prefix;
555   return Prefix;
556 }
557 
558 COMPILER_RT_VISIBILITY
559 const char *__llvm_profile_get_filename(void) {
560   int Length;
561   char *FilenameBuf;
562   const char *Filename;
563 
564   if (lprofCurFilename.Filename)
565     return lprofCurFilename.Filename;
566 
567   Length = getCurFilenameLength();
568   FilenameBuf = (char *)malloc(Length + 1);
569   if (!FilenameBuf) {
570     PROF_ERR("Failed to %s\n", "allocate memory.");
571     return "\0";
572   }
573   Filename = getCurFilename(FilenameBuf, 1);
574   if (!Filename)
575     return "\0";
576 
577   lprofCurFilename.Filename = FilenameBuf;
578   return FilenameBuf;
579 }
580 
581 /* This method is invoked by the runtime initialization hook
582  * InstrProfilingRuntime.o if it is linked in. Both user specified
583  * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
584  * environment variable can override this default value. */
585 COMPILER_RT_VISIBILITY
586 void __llvm_profile_initialize_file(void) {
587   const char *EnvFilenamePat;
588   const char *SelectedPat = NULL;
589   ProfileNameSpecifier PNS = PNS_unknown;
590   int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
591 
592   EnvFilenamePat = getFilenamePatFromEnv();
593   if (EnvFilenamePat) {
594     /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
595        at the  moment when __llvm_profile_write_file() gets executed. */
596     parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
597     return;
598   } else if (hasCommandLineOverrider) {
599     SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
600     PNS = PNS_command_line;
601   } else {
602     SelectedPat = NULL;
603     PNS = PNS_default;
604   }
605 
606   parseAndSetFilename(SelectedPat, PNS, 0);
607 }
608 
609 /* This API is directly called by the user application code. It has the
610  * highest precedence compared with LLVM_PROFILE_FILE environment variable
611  * and command line option -fprofile-instr-generate=<profile_name>.
612  */
613 COMPILER_RT_VISIBILITY
614 void __llvm_profile_set_filename(const char *FilenamePat) {
615   parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
616 }
617 
618 /* The public API for writing profile data into the file with name
619  * set by previous calls to __llvm_profile_set_filename or
620  * __llvm_profile_override_default_filename or
621  * __llvm_profile_initialize_file. */
622 COMPILER_RT_VISIBILITY
623 int __llvm_profile_write_file(void) {
624   int rc, Length;
625   const char *Filename;
626   char *FilenameBuf;
627   int PDeathSig = 0;
628 
629   if (lprofProfileDumped()) {
630     PROF_NOTE("Profile data not written to file: %s.\n",
631               "already written");
632     return 0;
633   }
634 
635   Length = getCurFilenameLength();
636   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
637   Filename = getCurFilename(FilenameBuf, 0);
638 
639   /* Check the filename. */
640   if (!Filename) {
641     PROF_ERR("Failed to write file : %s\n", "Filename not set");
642     return -1;
643   }
644 
645   /* Check if there is llvm/runtime version mismatch.  */
646   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
647     PROF_ERR("Runtime and instrumentation version mismatch : "
648              "expected %d, but get %d\n",
649              INSTR_PROF_RAW_VERSION,
650              (int)GET_VERSION(__llvm_profile_get_version()));
651     return -1;
652   }
653 
654   // Temporarily suspend getting SIGKILL when the parent exits.
655   PDeathSig = lprofSuspendSigKill();
656 
657   /* Write profile data to the file. */
658   rc = writeFile(Filename);
659   if (rc)
660     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
661 
662   // Restore SIGKILL.
663   if (PDeathSig == 1)
664     lprofRestoreSigKill();
665 
666   return rc;
667 }
668 
669 COMPILER_RT_VISIBILITY
670 int __llvm_profile_dump(void) {
671   if (!doMerging())
672     PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
673               " of previously dumped profile data : %s. Either use %%m "
674               "in profile name or change profile name before dumping.\n",
675               "online profile merging is not on");
676   int rc = __llvm_profile_write_file();
677   lprofSetProfileDumped();
678   return rc;
679 }
680 
681 /* Order file data will be saved in a file with suffx .order. */
682 static const char *OrderFileSuffix = ".order";
683 
684 COMPILER_RT_VISIBILITY
685 int __llvm_orderfile_write_file(void) {
686   int rc, Length, LengthBeforeAppend, SuffixLength;
687   const char *Filename;
688   char *FilenameBuf;
689   int PDeathSig = 0;
690 
691   SuffixLength = strlen(OrderFileSuffix);
692   Length = getCurFilenameLength() + SuffixLength;
693   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
694   Filename = getCurFilename(FilenameBuf, 1);
695 
696   /* Check the filename. */
697   if (!Filename) {
698     PROF_ERR("Failed to write file : %s\n", "Filename not set");
699     return -1;
700   }
701 
702   /* Append order file suffix */
703   LengthBeforeAppend = strlen(Filename);
704   memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength);
705   FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0';
706 
707   /* Check if there is llvm/runtime version mismatch.  */
708   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
709     PROF_ERR("Runtime and instrumentation version mismatch : "
710              "expected %d, but get %d\n",
711              INSTR_PROF_RAW_VERSION,
712              (int)GET_VERSION(__llvm_profile_get_version()));
713     return -1;
714   }
715 
716   // Temporarily suspend getting SIGKILL when the parent exits.
717   PDeathSig = lprofSuspendSigKill();
718 
719   /* Write order data to the file. */
720   rc = writeOrderFile(Filename);
721   if (rc)
722     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
723 
724   // Restore SIGKILL.
725   if (PDeathSig == 1)
726     lprofRestoreSigKill();
727 
728   return rc;
729 }
730 
731 COMPILER_RT_VISIBILITY
732 int __llvm_orderfile_dump(void) {
733   int rc = __llvm_orderfile_write_file();
734   return rc;
735 }
736 
737 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
738 
739 COMPILER_RT_VISIBILITY
740 int __llvm_profile_register_write_file_atexit(void) {
741   static int HasBeenRegistered = 0;
742 
743   if (HasBeenRegistered)
744     return 0;
745 
746   lprofSetupValueProfiler();
747 
748   HasBeenRegistered = 1;
749   return atexit(writeFileWithoutReturn);
750 }
751 
752 #endif
753