xref: /minix3/sys/external/bsd/compiler_rt/dist/lib/profile/InstrProfilingFile.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
16 
writeFile(FILE * File)17 static int writeFile(FILE *File) {
18   /* Match logic in __llvm_profile_write_buffer(). */
19   const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
20   const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
21   const uint64_t *CountersBegin = __llvm_profile_counters_begin();
22   const uint64_t *CountersEnd   = __llvm_profile_counters_end();
23   const char *NamesBegin = __llvm_profile_names_begin();
24   const char *NamesEnd   = __llvm_profile_names_end();
25 
26   /* Calculate size of sections. */
27   const uint64_t DataSize = DataEnd - DataBegin;
28   const uint64_t CountersSize = CountersEnd - CountersBegin;
29   const uint64_t NamesSize = NamesEnd - NamesBegin;
30   const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
31 
32   /* Enough zeroes for padding. */
33   const char Zeroes[sizeof(uint64_t)] = {0};
34 
35   /* Create the header. */
36   uint64_t Header[PROFILE_HEADER_SIZE];
37   Header[0] = __llvm_profile_get_magic();
38   Header[1] = __llvm_profile_get_version();
39   Header[2] = DataSize;
40   Header[3] = CountersSize;
41   Header[4] = NamesSize;
42   Header[5] = (uintptr_t)CountersBegin;
43   Header[6] = (uintptr_t)NamesBegin;
44 
45   /* Write the data. */
46 #define CHECK_fwrite(Data, Size, Length, File) \
47   do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
48   CHECK_fwrite(Header,        sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
49   CHECK_fwrite(DataBegin,     sizeof(__llvm_profile_data), DataSize, File);
50   CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
51   CHECK_fwrite(NamesBegin,    sizeof(char), NamesSize, File);
52   CHECK_fwrite(Zeroes,        sizeof(char), Padding, File);
53 #undef CHECK_fwrite
54 
55   return 0;
56 }
57 
writeFileWithName(const char * OutputName)58 static int writeFileWithName(const char *OutputName) {
59   int RetVal;
60   FILE *OutputFile;
61   if (!OutputName || !OutputName[0])
62     return -1;
63 
64   /* Append to the file to support profiling multiple shared objects. */
65   OutputFile = fopen(OutputName, "a");
66   if (!OutputFile)
67     return -1;
68 
69   RetVal = writeFile(OutputFile);
70 
71   fclose(OutputFile);
72   return RetVal;
73 }
74 
75 __attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
76 __attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
77 
setFilename(const char * Filename,int OwnsFilename)78 static void setFilename(const char *Filename, int OwnsFilename) {
79   if (__llvm_profile_OwnsFilename)
80     free(UNCONST(__llvm_profile_CurrentFilename));
81 
82   __llvm_profile_CurrentFilename = Filename;
83   __llvm_profile_OwnsFilename = OwnsFilename;
84 }
85 
truncateCurrentFile(void)86 static void truncateCurrentFile(void) {
87   const char *Filename = __llvm_profile_CurrentFilename;
88   if (!Filename || !Filename[0])
89     return;
90 
91   /* Truncate the file.  Later we'll reopen and append. */
92   FILE *File = fopen(Filename, "w");
93   if (!File)
94     return;
95   fclose(File);
96 }
97 
setDefaultFilename(void)98 static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
99 
100 int getpid(void);
setFilenameFromEnvironment(void)101 static int setFilenameFromEnvironment(void) {
102   const char *Filename = getenv("LLVM_PROFILE_FILE");
103   if (!Filename || !Filename[0])
104     return -1;
105 
106   /* Check the filename for "%p", which indicates a pid-substitution. */
107 #define MAX_PID_SIZE 16
108   char PidChars[MAX_PID_SIZE] = {0};
109   int NumPids = 0;
110   int PidLength = 0;
111   int I;
112   for (I = 0; Filename[I]; ++I)
113     if (Filename[I] == '%' && Filename[++I] == 'p')
114       if (!NumPids++) {
115         PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
116         if (PidLength <= 0)
117           return -1;
118       }
119   if (!NumPids) {
120     setFilename(Filename, 0);
121     return 0;
122   }
123 
124   /* Allocate enough space for the substituted filename. */
125   char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
126   if (!Allocated)
127     return -1;
128 
129   /* Construct the new filename. */
130   int J;
131   for (I = 0, J = 0; Filename[I]; ++I)
132     if (Filename[I] == '%') {
133       if (Filename[++I] == 'p') {
134         memcpy(Allocated + J, PidChars, PidLength);
135         J += PidLength;
136       }
137       /* Drop any unknown substitutions. */
138     } else
139       Allocated[J++] = Filename[I];
140   Allocated[J] = 0;
141 
142   /* Use the computed name. */
143   setFilename(Allocated, 1);
144   return 0;
145 }
146 
setFilenameAutomatically(void)147 static void setFilenameAutomatically(void) {
148   if (!setFilenameFromEnvironment())
149     return;
150 
151   setDefaultFilename();
152 }
153 
154 __attribute__((visibility("hidden")))
__llvm_profile_initialize_file(void)155 void __llvm_profile_initialize_file(void) {
156   /* Check if the filename has been initialized. */
157   if (__llvm_profile_CurrentFilename)
158     return;
159 
160   /* Detect the filename and truncate. */
161   setFilenameAutomatically();
162   truncateCurrentFile();
163 }
164 
165 __attribute__((visibility("hidden")))
__llvm_profile_set_filename(const char * Filename)166 void __llvm_profile_set_filename(const char *Filename) {
167   setFilename(Filename, 0);
168   truncateCurrentFile();
169 }
170 
171 __attribute__((visibility("hidden")))
__llvm_profile_write_file(void)172 int __llvm_profile_write_file(void) {
173   /* Check the filename. */
174   if (!__llvm_profile_CurrentFilename)
175     return -1;
176 
177   /* Write the file. */
178   return writeFileWithName(__llvm_profile_CurrentFilename);
179 }
180 
writeFileWithoutReturn(void)181 static void writeFileWithoutReturn(void) {
182   __llvm_profile_write_file();
183 }
184 
185 __attribute__((visibility("hidden")))
__llvm_profile_register_write_file_atexit(void)186 int __llvm_profile_register_write_file_atexit(void) {
187   static int HasBeenRegistered = 0;
188 
189   if (HasBeenRegistered)
190     return 0;
191 
192   HasBeenRegistered = 1;
193   return atexit(writeFileWithoutReturn);
194 }
195