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 static void initFileWriter(ProfDataWriter *This, FILE *File) {
115   This->Write = fileWriter;
116   This->WriterCtx = File;
117 }
118 
119 COMPILER_RT_VISIBILITY ProfBufferIO *
120 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
121   FreeHook = &free;
122   DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
123   VPBufferSize = BufferSz;
124   ProfDataWriter *fileWriter =
125       (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1);
126   initFileWriter(fileWriter, File);
127   ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
128   IO->OwnFileWriter = 1;
129   return IO;
130 }
131 
132 static void setupIOBuffer() {
133   const char *BufferSzStr = 0;
134   BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
135   if (BufferSzStr && BufferSzStr[0]) {
136     VPBufferSize = atoi(BufferSzStr);
137     DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
138   }
139 }
140 
141 /* Read profile data in \c ProfileFile and merge with in-memory
142    profile counters. Returns -1 if there is fatal error, otheriwse
143    0 is returned. Returning 0 does not mean merge is actually
144    performed. If merge is actually done, *MergeDone is set to 1.
145 */
146 static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
147   uint64_t ProfileFileSize;
148   char *ProfileBuffer;
149 
150   if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
151     PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
152              strerror(errno));
153     return -1;
154   }
155   ProfileFileSize = ftell(ProfileFile);
156 
157   /* Restore file offset.  */
158   if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
159     PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
160              strerror(errno));
161     return -1;
162   }
163 
164   /* Nothing to merge.  */
165   if (ProfileFileSize < sizeof(__llvm_profile_header)) {
166     if (ProfileFileSize)
167       PROF_WARN("Unable to merge profile data: %s\n",
168                 "source profile file is too small.");
169     return 0;
170   }
171 
172   ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
173                        fileno(ProfileFile), 0);
174   if (ProfileBuffer == MAP_FAILED) {
175     PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
176              strerror(errno));
177     return -1;
178   }
179 
180   if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
181     (void)munmap(ProfileBuffer, ProfileFileSize);
182     PROF_WARN("Unable to merge profile data: %s\n",
183               "source profile file is not compatible.");
184     return 0;
185   }
186 
187   /* Now start merging */
188   __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
189 
190   // Truncate the file in case merging of value profile did not happend to
191   // prevent from leaving garbage data at the end of the profile file.
192   COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer());
193 
194   (void)munmap(ProfileBuffer, ProfileFileSize);
195   *MergeDone = 1;
196 
197   return 0;
198 }
199 
200 /* Create the directory holding the file, if needed. */
201 static void createProfileDir(const char *Filename) {
202   size_t Length = strlen(Filename);
203   if (lprofFindFirstDirSeparator(Filename)) {
204     char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
205     strncpy(Copy, Filename, Length + 1);
206     __llvm_profile_recursive_mkdir(Copy);
207   }
208 }
209 
210 /* Open the profile data for merging. It opens the file in r+b mode with
211  * file locking.  If the file has content which is compatible with the
212  * current process, it also reads in the profile data in the file and merge
213  * it with in-memory counters. After the profile data is merged in memory,
214  * the original profile data is truncated and gets ready for the profile
215  * dumper. With profile merging enabled, each executable as well as any of
216  * its instrumented shared libraries dump profile data into their own data file.
217 */
218 static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
219   FILE *ProfileFile;
220   int rc;
221 
222   createProfileDir(ProfileFileName);
223   ProfileFile = lprofOpenFileEx(ProfileFileName);
224   if (!ProfileFile)
225     return NULL;
226 
227   rc = doProfileMerging(ProfileFile, MergeDone);
228   if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
229       fseek(ProfileFile, 0L, SEEK_SET) == -1) {
230     PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
231              strerror(errno));
232     fclose(ProfileFile);
233     return NULL;
234   }
235   return ProfileFile;
236 }
237 
238 /* Write profile data to file \c OutputName.  */
239 static int writeFile(const char *OutputName) {
240   int RetVal;
241   FILE *OutputFile;
242 
243   int MergeDone = 0;
244   VPMergeHook = &lprofMergeValueProfData;
245   if (!doMerging())
246     OutputFile = fopen(OutputName, "ab");
247   else
248     OutputFile = openFileForMerging(OutputName, &MergeDone);
249 
250   if (!OutputFile)
251     return -1;
252 
253   FreeHook = &free;
254   setupIOBuffer();
255   ProfDataWriter fileWriter;
256   initFileWriter(&fileWriter, OutputFile);
257   RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
258 
259   fclose(OutputFile);
260   return RetVal;
261 }
262 
263 static void truncateCurrentFile(void) {
264   const char *Filename;
265   char *FilenameBuf;
266   FILE *File;
267   int Length;
268 
269   Length = getCurFilenameLength();
270   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
271   Filename = getCurFilename(FilenameBuf, 0);
272   if (!Filename)
273     return;
274 
275   /* By pass file truncation to allow online raw profile
276    * merging. */
277   if (lprofCurFilename.MergePoolSize)
278     return;
279 
280   createProfileDir(Filename);
281 
282   /* Truncate the file.  Later we'll reopen and append. */
283   File = fopen(Filename, "w");
284   if (!File)
285     return;
286   fclose(File);
287 }
288 
289 static const char *DefaultProfileName = "default.profraw";
290 static void resetFilenameToDefault(void) {
291   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
292     free((void *)lprofCurFilename.FilenamePat);
293   }
294   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
295   lprofCurFilename.FilenamePat = DefaultProfileName;
296   lprofCurFilename.PNS = PNS_default;
297 }
298 
299 static int containsMergeSpecifier(const char *FilenamePat, int I) {
300   return (FilenamePat[I] == 'm' ||
301           (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
302            /* If FilenamePat[I] is not '\0', the next byte is guaranteed
303             * to be in-bound as the string is null terminated. */
304            FilenamePat[I + 1] == 'm'));
305 }
306 
307 /* Parses the pattern string \p FilenamePat and stores the result to
308  * lprofcurFilename structure. */
309 static int parseFilenamePattern(const char *FilenamePat,
310                                 unsigned CopyFilenamePat) {
311   int NumPids = 0, NumHosts = 0, I;
312   char *PidChars = &lprofCurFilename.PidChars[0];
313   char *Hostname = &lprofCurFilename.Hostname[0];
314   int MergingEnabled = 0;
315 
316   /* Clean up cached prefix and filename.  */
317   if (lprofCurFilename.ProfilePathPrefix)
318     free((void *)lprofCurFilename.ProfilePathPrefix);
319   if (lprofCurFilename.Filename)
320     free((void *)lprofCurFilename.Filename);
321 
322   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
323     free((void *)lprofCurFilename.FilenamePat);
324   }
325 
326   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
327 
328   if (!CopyFilenamePat)
329     lprofCurFilename.FilenamePat = FilenamePat;
330   else {
331     lprofCurFilename.FilenamePat = strdup(FilenamePat);
332     lprofCurFilename.OwnsFilenamePat = 1;
333   }
334   /* Check the filename for "%p", which indicates a pid-substitution. */
335   for (I = 0; FilenamePat[I]; ++I)
336     if (FilenamePat[I] == '%') {
337       if (FilenamePat[++I] == 'p') {
338         if (!NumPids++) {
339           if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
340             PROF_WARN("Unable to get pid for filename pattern %s. Using the "
341                       "default name.",
342                       FilenamePat);
343             return -1;
344           }
345         }
346       } else if (FilenamePat[I] == 'h') {
347         if (!NumHosts++)
348           if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
349             PROF_WARN("Unable to get hostname for filename pattern %s. Using "
350                       "the default name.",
351                       FilenamePat);
352             return -1;
353           }
354       } else if (containsMergeSpecifier(FilenamePat, I)) {
355         if (MergingEnabled) {
356           PROF_WARN("%%m specifier can only be specified once in %s.\n",
357                     FilenamePat);
358           return -1;
359         }
360         MergingEnabled = 1;
361         if (FilenamePat[I] == 'm')
362           lprofCurFilename.MergePoolSize = 1;
363         else {
364           lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
365           I++; /* advance to 'm' */
366         }
367       }
368     }
369 
370   lprofCurFilename.NumPids = NumPids;
371   lprofCurFilename.NumHosts = NumHosts;
372   return 0;
373 }
374 
375 static void parseAndSetFilename(const char *FilenamePat,
376                                 ProfileNameSpecifier PNS,
377                                 unsigned CopyFilenamePat) {
378 
379   const char *OldFilenamePat = lprofCurFilename.FilenamePat;
380   ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
381 
382   if (PNS < OldPNS)
383     return;
384 
385   if (!FilenamePat)
386     FilenamePat = DefaultProfileName;
387 
388   if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
389     lprofCurFilename.PNS = PNS;
390     return;
391   }
392 
393   /* When PNS >= OldPNS, the last one wins. */
394   if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
395     resetFilenameToDefault();
396   lprofCurFilename.PNS = PNS;
397 
398   if (!OldFilenamePat) {
399     if (getenv("LLVM_PROFILE_VERBOSE"))
400       PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
401                 lprofCurFilename.FilenamePat, getPNSStr(PNS));
402   } else {
403     if (getenv("LLVM_PROFILE_VERBOSE"))
404       PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
405                 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
406                 getPNSStr(PNS));
407   }
408 
409   truncateCurrentFile();
410 }
411 
412 /* Return buffer length that is required to store the current profile
413  * filename with PID and hostname substitutions. */
414 /* The length to hold uint64_t followed by 2 digit pool id including '_' */
415 #define SIGLEN 24
416 static int getCurFilenameLength() {
417   int Len;
418   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
419     return 0;
420 
421   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
422         lprofCurFilename.MergePoolSize))
423     return strlen(lprofCurFilename.FilenamePat);
424 
425   Len = strlen(lprofCurFilename.FilenamePat) +
426         lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
427         lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
428   if (lprofCurFilename.MergePoolSize)
429     Len += SIGLEN;
430   return Len;
431 }
432 
433 /* Return the pointer to the current profile file name (after substituting
434  * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
435  * to store the resulting filename. If no substitution is needed, the
436  * current filename pattern string is directly returned, unless ForceUseBuf
437  * is enabled. */
438 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
439   int I, J, PidLength, HostNameLength, FilenamePatLength;
440   const char *FilenamePat = lprofCurFilename.FilenamePat;
441 
442   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
443     return 0;
444 
445   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
446         lprofCurFilename.MergePoolSize)) {
447     if (!ForceUseBuf)
448       return lprofCurFilename.FilenamePat;
449 
450     FilenamePatLength = strlen(lprofCurFilename.FilenamePat);
451     memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);
452     FilenameBuf[FilenamePatLength] = '\0';
453     return FilenameBuf;
454   }
455 
456   PidLength = strlen(lprofCurFilename.PidChars);
457   HostNameLength = strlen(lprofCurFilename.Hostname);
458   /* Construct the new filename. */
459   for (I = 0, J = 0; FilenamePat[I]; ++I)
460     if (FilenamePat[I] == '%') {
461       if (FilenamePat[++I] == 'p') {
462         memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
463         J += PidLength;
464       } else if (FilenamePat[I] == 'h') {
465         memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
466         J += HostNameLength;
467       } else if (containsMergeSpecifier(FilenamePat, I)) {
468         char LoadModuleSignature[SIGLEN];
469         int S;
470         int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
471         S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d",
472                      lprofGetLoadModuleSignature(), ProfilePoolId);
473         if (S == -1 || S > SIGLEN)
474           S = SIGLEN;
475         memcpy(FilenameBuf + J, LoadModuleSignature, S);
476         J += S;
477         if (FilenamePat[I] != 'm')
478           I++;
479       }
480       /* Drop any unknown substitutions. */
481     } else
482       FilenameBuf[J++] = FilenamePat[I];
483   FilenameBuf[J] = 0;
484 
485   return FilenameBuf;
486 }
487 
488 /* Returns the pointer to the environment variable
489  * string. Returns null if the env var is not set. */
490 static const char *getFilenamePatFromEnv(void) {
491   const char *Filename = getenv("LLVM_PROFILE_FILE");
492   if (!Filename || !Filename[0])
493     return 0;
494   return Filename;
495 }
496 
497 COMPILER_RT_VISIBILITY
498 const char *__llvm_profile_get_path_prefix(void) {
499   int Length;
500   char *FilenameBuf, *Prefix;
501   const char *Filename, *PrefixEnd;
502 
503   if (lprofCurFilename.ProfilePathPrefix)
504     return lprofCurFilename.ProfilePathPrefix;
505 
506   Length = getCurFilenameLength();
507   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
508   Filename = getCurFilename(FilenameBuf, 0);
509   if (!Filename)
510     return "\0";
511 
512   PrefixEnd = lprofFindLastDirSeparator(Filename);
513   if (!PrefixEnd)
514     return "\0";
515 
516   Length = PrefixEnd - Filename + 1;
517   Prefix = (char *)malloc(Length + 1);
518   if (!Prefix) {
519     PROF_ERR("Failed to %s\n", "allocate memory.");
520     return "\0";
521   }
522   memcpy(Prefix, Filename, Length);
523   Prefix[Length] = '\0';
524   lprofCurFilename.ProfilePathPrefix = Prefix;
525   return Prefix;
526 }
527 
528 COMPILER_RT_VISIBILITY
529 const char *__llvm_profile_get_filename(void) {
530   int Length;
531   char *FilenameBuf;
532   const char *Filename;
533 
534   if (lprofCurFilename.Filename)
535     return lprofCurFilename.Filename;
536 
537   Length = getCurFilenameLength();
538   FilenameBuf = (char *)malloc(Length + 1);
539   if (!FilenameBuf) {
540     PROF_ERR("Failed to %s\n", "allocate memory.");
541     return "\0";
542   }
543   Filename = getCurFilename(FilenameBuf, 1);
544   if (!Filename)
545     return "\0";
546 
547   lprofCurFilename.Filename = FilenameBuf;
548   return FilenameBuf;
549 }
550 
551 /* This method is invoked by the runtime initialization hook
552  * InstrProfilingRuntime.o if it is linked in. Both user specified
553  * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
554  * environment variable can override this default value. */
555 COMPILER_RT_VISIBILITY
556 void __llvm_profile_initialize_file(void) {
557   const char *EnvFilenamePat;
558   const char *SelectedPat = NULL;
559   ProfileNameSpecifier PNS = PNS_unknown;
560   int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
561 
562   EnvFilenamePat = getFilenamePatFromEnv();
563   if (EnvFilenamePat) {
564     /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
565        at the  moment when __llvm_profile_write_file() gets executed. */
566     parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
567     return;
568   } else if (hasCommandLineOverrider) {
569     SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
570     PNS = PNS_command_line;
571   } else {
572     SelectedPat = NULL;
573     PNS = PNS_default;
574   }
575 
576   parseAndSetFilename(SelectedPat, PNS, 0);
577 }
578 
579 /* This API is directly called by the user application code. It has the
580  * highest precedence compared with LLVM_PROFILE_FILE environment variable
581  * and command line option -fprofile-instr-generate=<profile_name>.
582  */
583 COMPILER_RT_VISIBILITY
584 void __llvm_profile_set_filename(const char *FilenamePat) {
585   parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
586 }
587 
588 /* The public API for writing profile data into the file with name
589  * set by previous calls to __llvm_profile_set_filename or
590  * __llvm_profile_override_default_filename or
591  * __llvm_profile_initialize_file. */
592 COMPILER_RT_VISIBILITY
593 int __llvm_profile_write_file(void) {
594   int rc, Length;
595   const char *Filename;
596   char *FilenameBuf;
597   int PDeathSig = 0;
598 
599   if (lprofProfileDumped()) {
600     PROF_NOTE("Profile data not written to file: %s.\n",
601               "already written");
602     return 0;
603   }
604 
605   Length = getCurFilenameLength();
606   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
607   Filename = getCurFilename(FilenameBuf, 0);
608 
609   /* Check the filename. */
610   if (!Filename) {
611     PROF_ERR("Failed to write file : %s\n", "Filename not set");
612     return -1;
613   }
614 
615   /* Check if there is llvm/runtime version mismatch.  */
616   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
617     PROF_ERR("Runtime and instrumentation version mismatch : "
618              "expected %d, but get %d\n",
619              INSTR_PROF_RAW_VERSION,
620              (int)GET_VERSION(__llvm_profile_get_version()));
621     return -1;
622   }
623 
624   // Temporarily suspend getting SIGKILL when the parent exits.
625   PDeathSig = lprofSuspendSigKill();
626 
627   /* Write profile data to the file. */
628   rc = writeFile(Filename);
629   if (rc)
630     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
631 
632   // Restore SIGKILL.
633   if (PDeathSig == 1)
634     lprofRestoreSigKill();
635 
636   return rc;
637 }
638 
639 COMPILER_RT_VISIBILITY
640 int __llvm_profile_dump(void) {
641   if (!doMerging())
642     PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
643               " of previously dumped profile data : %s. Either use %%m "
644               "in profile name or change profile name before dumping.\n",
645               "online profile merging is not on");
646   int rc = __llvm_profile_write_file();
647   lprofSetProfileDumped();
648   return rc;
649 }
650 
651 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
652 
653 COMPILER_RT_VISIBILITY
654 int __llvm_profile_register_write_file_atexit(void) {
655   static int HasBeenRegistered = 0;
656 
657   if (HasBeenRegistered)
658     return 0;
659 
660   lprofSetupValueProfiler();
661 
662   HasBeenRegistered = 1;
663   return atexit(writeFileWithoutReturn);
664 }
665 
666 #endif
667