1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
2 |*
3 |*                     The LLVM Compiler Infrastructure
4 |*
5 |* This file is distributed under the University of Illinois Open Source
6 |* License. See LICENSE.TXT for details.
7 |*
8 \*===----------------------------------------------------------------------===*/
9 
10 #include "InstrProfiling.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 static int writeFile(FILE *File) {
16   /* Match logic in __llvm_profile_write_buffer(). */
17   const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
18   const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
19   const uint64_t *CountersBegin = __llvm_profile_counters_begin();
20   const uint64_t *CountersEnd   = __llvm_profile_counters_end();
21   const char *NamesBegin = __llvm_profile_names_begin();
22   const char *NamesEnd   = __llvm_profile_names_end();
23 
24   /* Calculate size of sections. */
25   const uint64_t DataSize = DataEnd - DataBegin;
26   const uint64_t CountersSize = CountersEnd - CountersBegin;
27   const uint64_t NamesSize = NamesEnd - NamesBegin;
28 
29   /* Create the header. */
30   uint64_t Header[PROFILE_HEADER_SIZE] = {
31     __llvm_profile_get_magic(),
32     __llvm_profile_get_version(),
33     DataSize,
34     CountersSize,
35     NamesSize,
36     (uintptr_t)CountersBegin,
37     (uintptr_t)NamesBegin
38   };
39 
40   /* Write the data. */
41 #define CHECK_fwrite(Data, Size, Length, File) \
42   do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
43   CHECK_fwrite(Header,        sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
44   CHECK_fwrite(DataBegin,     sizeof(__llvm_profile_data), DataSize, File);
45   CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
46   CHECK_fwrite(NamesBegin,    sizeof(char), NamesSize, File);
47 #undef CHECK_fwrite
48 
49    return 0;
50 }
51 
52 static int writeFileWithName(const char *OutputName) {
53   int RetVal;
54   FILE *OutputFile;
55   if (!OutputName || !OutputName[0])
56     return -1;
57   OutputFile = fopen(OutputName, "w");
58   if (!OutputFile)
59     return -1;
60 
61   RetVal = writeFile(OutputFile);
62 
63   fclose(OutputFile);
64   return RetVal;
65 }
66 
67 static const char *CurrentFilename = NULL;
68 void __llvm_profile_set_filename(const char *Filename) {
69   CurrentFilename = Filename;
70 }
71 
72 int getpid(void);
73 int __llvm_profile_write_file(void) {
74   char *AllocatedFilename = NULL;
75   int I, J;
76   int RetVal;
77 
78 #define MAX_PID_SIZE 16
79   char PidChars[MAX_PID_SIZE] = { 0 };
80   int PidLength = 0;
81   int NumPids = 0;
82 
83   /* Get the filename. */
84   const char *Filename = CurrentFilename;
85 #define UPDATE_FILENAME(NextFilename) \
86   if (!Filename || !Filename[0]) Filename = NextFilename
87   UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
88   UPDATE_FILENAME("default.profraw");
89 #undef UPDATE_FILENAME
90 
91   /* Check the filename for "%p", which indicates a pid-substitution. */
92   for (I = 0; Filename[I]; ++I)
93     if (Filename[I] == '%' && Filename[++I] == 'p')
94       if (!NumPids++) {
95         PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
96         if (PidLength <= 0)
97           return -1;
98       }
99   if (NumPids) {
100     /* Allocate enough space for the substituted filename. */
101     AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
102     if (!AllocatedFilename)
103       return -1;
104 
105     /* Construct the new filename. */
106     for (I = 0, J = 0; Filename[I]; ++I)
107       if (Filename[I] == '%') {
108         if (Filename[++I] == 'p') {
109           memcpy(AllocatedFilename + J, PidChars, PidLength);
110           J += PidLength;
111         }
112         /* Drop any unknown substitutions. */
113       } else
114         AllocatedFilename[J++] = Filename[I];
115     AllocatedFilename[J] = 0;
116 
117     /* Actually use the computed name. */
118     Filename = AllocatedFilename;
119   }
120 
121   /* Write the file. */
122   RetVal = writeFileWithName(Filename);
123 
124   /* Free the filename. */
125   if (AllocatedFilename)
126     free(AllocatedFilename);
127 
128   return RetVal;
129 }
130 
131 static void writeFileWithoutReturn(void) {
132   __llvm_profile_write_file();
133 }
134 
135 int __llvm_profile_register_write_file_atexit(void) {
136   static int HasBeenRegistered = 0;
137 
138   if (HasBeenRegistered)
139     return 0;
140 
141   HasBeenRegistered = 1;
142   return atexit(writeFileWithoutReturn);
143 }
144