]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingUtil.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / profile / InstrProfilingUtil.c
1 /*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
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 #ifdef _WIN32
10 #include <direct.h>
11 #include <process.h>
12 #include <windows.h>
13 #include "WindowsMMap.h"
14 #else
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #endif
21
22 #ifdef COMPILER_RT_HAS_UNAME
23 #include <sys/utsname.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #if defined(__linux__)
30 #include <signal.h>
31 #include <sys/prctl.h>
32 #endif
33
34 #include "InstrProfiling.h"
35 #include "InstrProfilingUtil.h"
36
37 COMPILER_RT_WEAK unsigned lprofDirMode = 0755;
38
39 COMPILER_RT_VISIBILITY
40 void __llvm_profile_recursive_mkdir(char *path) {
41   int i;
42
43   for (i = 1; path[i] != '\0'; ++i) {
44     char save = path[i];
45     if (!IS_DIR_SEPARATOR(path[i]))
46       continue;
47     path[i] = '\0';
48 #ifdef _WIN32
49     _mkdir(path);
50 #else
51     /* Some of these will fail, ignore it. */
52     mkdir(path, __llvm_profile_get_dir_mode());
53 #endif
54     path[i] = save;
55   }
56 }
57
58 COMPILER_RT_VISIBILITY
59 void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
60
61 COMPILER_RT_VISIBILITY
62 unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
63
64 #if COMPILER_RT_HAS_ATOMICS != 1
65 COMPILER_RT_VISIBILITY
66 uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
67   void *R = *Ptr;
68   if (R == OldV) {
69     *Ptr = NewV;
70     return 1;
71   }
72   return 0;
73 }
74 COMPILER_RT_VISIBILITY
75 void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
76   void *Old = *Mem;
77   *((char **)Mem) += ByteIncr;
78   return Old;
79 }
80
81 #endif
82
83 #ifdef _WIN32
84 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
85   WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
86   DWORD BufferSize = sizeof(Buffer);
87   BOOL Result =
88       GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
89   if (!Result)
90     return -1;
91   if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
92     return -1;
93   return 0;
94 }
95 #elif defined(COMPILER_RT_HAS_UNAME)
96 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
97   struct utsname N;
98   int R = uname(&N);
99   if (R >= 0) {
100     strncpy(Name, N.nodename, Len);
101     return 0;
102   }
103   return R;
104 }
105 #endif
106
107 COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
108 #ifdef COMPILER_RT_HAS_FCNTL_LCK
109   struct flock s_flock;
110
111   s_flock.l_whence = SEEK_SET;
112   s_flock.l_start = 0;
113   s_flock.l_len = 0; /* Until EOF.  */
114   s_flock.l_pid = getpid();
115   s_flock.l_type = F_WRLCK;
116
117   while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
118     if (errno != EINTR) {
119       if (errno == ENOLCK) {
120         return -1;
121       }
122       break;
123     }
124   }
125   return 0;
126 #else
127   flock(fd, LOCK_EX);
128   return 0;
129 #endif
130 }
131
132 COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
133 #ifdef COMPILER_RT_HAS_FCNTL_LCK
134   struct flock s_flock;
135
136   s_flock.l_whence = SEEK_SET;
137   s_flock.l_start = 0;
138   s_flock.l_len = 0; /* Until EOF.  */
139   s_flock.l_pid = getpid();
140   s_flock.l_type = F_UNLCK;
141
142   while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
143     if (errno != EINTR) {
144       if (errno == ENOLCK) {
145         return -1;
146       }
147       break;
148     }
149   }
150   return 0;
151 #else
152   flock(fd, LOCK_UN);
153   return 0;
154 #endif
155 }
156
157 COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {
158   int fd;
159 #if defined(_WIN32)
160   fd = _fileno(F);
161 #else
162   fd = fileno(F);
163 #endif
164   return lprofLockFd(fd);
165 }
166
167 COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {
168   int fd;
169 #if defined(_WIN32)
170   fd = _fileno(F);
171 #else
172   fd = fileno(F);
173 #endif
174   return lprofUnlockFd(fd);
175 }
176
177 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
178   FILE *f;
179   int fd;
180 #ifdef COMPILER_RT_HAS_FCNTL_LCK
181   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
182   if (fd < 0)
183     return NULL;
184
185   if (lprofLockFd(fd) != 0)
186     PROF_WARN("Data may be corrupted during profile merging : %s\n",
187               "Fail to obtain file lock due to system limit.");
188
189   f = fdopen(fd, "r+b");
190 #elif defined(_WIN32)
191   // FIXME: Use the wide variants to handle Unicode filenames.
192   HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE,
193                          FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
194                          FILE_ATTRIBUTE_NORMAL, 0);
195   if (h == INVALID_HANDLE_VALUE)
196     return NULL;
197
198   fd = _open_osfhandle((intptr_t)h, 0);
199   if (fd == -1) {
200     CloseHandle(h);
201     return NULL;
202   }
203
204   if (lprofLockFd(fd) != 0)
205     PROF_WARN("Data may be corrupted during profile merging : %s\n",
206               "Fail to obtain file lock due to system limit.");
207
208   f = _fdopen(fd, "r+b");
209   if (f == 0) {
210     CloseHandle(h);
211     return NULL;
212   }
213 #else
214   /* Worst case no locking applied.  */
215   PROF_WARN("Concurrent file access is not supported : %s\n",
216             "lack file locking");
217   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
218   if (fd < 0)
219     return NULL;
220   f = fdopen(fd, "r+b");
221 #endif
222
223   return f;
224 }
225
226 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
227                                                       size_t *PrefixLen) {
228   const char *Prefix = getenv("GCOV_PREFIX");
229   const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
230
231   *PrefixLen = 0;
232   *PrefixStrip = 0;
233   if (Prefix == NULL || Prefix[0] == '\0')
234     return NULL;
235
236   if (PrefixStripStr) {
237     *PrefixStrip = atoi(PrefixStripStr);
238
239     /* Negative GCOV_PREFIX_STRIP values are ignored */
240     if (*PrefixStrip < 0)
241       *PrefixStrip = 0;
242   } else {
243     *PrefixStrip = 0;
244   }
245   *PrefixLen = strlen(Prefix);
246
247   return Prefix;
248 }
249
250 COMPILER_RT_VISIBILITY void
251 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
252                      size_t PrefixLen, int PrefixStrip) {
253
254   const char *Ptr;
255   int Level;
256   const char *StrippedPathStr = PathStr;
257
258   for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
259     if (*Ptr == '\0')
260       break;
261
262     if (!IS_DIR_SEPARATOR(*Ptr))
263       continue;
264
265     StrippedPathStr = Ptr;
266     ++Level;
267   }
268
269   memcpy(Dest, Prefix, PrefixLen);
270
271   if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
272     Dest[PrefixLen++] = DIR_SEPARATOR;
273
274   memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
275 }
276
277 COMPILER_RT_VISIBILITY const char *
278 lprofFindFirstDirSeparator(const char *Path) {
279   const char *Sep = strchr(Path, DIR_SEPARATOR);
280 #if defined(DIR_SEPARATOR_2)
281   const char *Sep2 = strchr(Path, DIR_SEPARATOR_2);
282   if (Sep2 && (!Sep || Sep2 < Sep))
283     Sep = Sep2;
284 #endif
285   return Sep;
286 }
287
288 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
289   const char *Sep = strrchr(Path, DIR_SEPARATOR);
290 #if defined(DIR_SEPARATOR_2)
291   const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2);
292   if (Sep2 && (!Sep || Sep2 > Sep))
293     Sep = Sep2;
294 #endif
295   return Sep;
296 }
297
298 COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
299 #if defined(__linux__)
300   int PDeachSig = 0;
301   /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
302   if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
303     prctl(PR_SET_PDEATHSIG, 0);
304   return (PDeachSig == SIGKILL);
305 #else
306   return 0;
307 #endif
308 }
309
310 COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
311 #if defined(__linux__)
312   prctl(PR_SET_PDEATHSIG, SIGKILL);
313 #endif
314 }