]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/profile/InstrProfilingUtil.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / 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, 0, 0,
193                          OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
194   if (h == INVALID_HANDLE_VALUE)
195     return NULL;
196
197   fd = _open_osfhandle((intptr_t)h, 0);
198   if (fd == -1) {
199     CloseHandle(h);
200     return NULL;
201   }
202
203   f = _fdopen(fd, "r+b");
204   if (f == 0) {
205     CloseHandle(h);
206     return NULL;
207   }
208 #else
209   /* Worst case no locking applied.  */
210   PROF_WARN("Concurrent file access is not supported : %s\n",
211             "lack file locking");
212   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
213   if (fd < 0)
214     return NULL;
215   f = fdopen(fd, "r+b");
216 #endif
217
218   return f;
219 }
220
221 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
222                                                       size_t *PrefixLen) {
223   const char *Prefix = getenv("GCOV_PREFIX");
224   const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
225
226   *PrefixLen = 0;
227   *PrefixStrip = 0;
228   if (Prefix == NULL || Prefix[0] == '\0')
229     return NULL;
230
231   if (PrefixStripStr) {
232     *PrefixStrip = atoi(PrefixStripStr);
233
234     /* Negative GCOV_PREFIX_STRIP values are ignored */
235     if (*PrefixStrip < 0)
236       *PrefixStrip = 0;
237   } else {
238     *PrefixStrip = 0;
239   }
240   *PrefixLen = strlen(Prefix);
241
242   return Prefix;
243 }
244
245 COMPILER_RT_VISIBILITY void
246 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
247                      size_t PrefixLen, int PrefixStrip) {
248
249   const char *Ptr;
250   int Level;
251   const char *StrippedPathStr = PathStr;
252
253   for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
254     if (*Ptr == '\0')
255       break;
256
257     if (!IS_DIR_SEPARATOR(*Ptr))
258       continue;
259
260     StrippedPathStr = Ptr;
261     ++Level;
262   }
263
264   memcpy(Dest, Prefix, PrefixLen);
265
266   if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
267     Dest[PrefixLen++] = DIR_SEPARATOR;
268
269   memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
270 }
271
272 COMPILER_RT_VISIBILITY const char *
273 lprofFindFirstDirSeparator(const char *Path) {
274   const char *Sep = strchr(Path, DIR_SEPARATOR);
275 #if defined(DIR_SEPARATOR_2)
276   const char *Sep2 = strchr(Path, DIR_SEPARATOR_2);
277   if (Sep2 && (!Sep || Sep2 < Sep))
278     Sep = Sep2;
279 #endif
280   return Sep;
281 }
282
283 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
284   const char *Sep = strrchr(Path, DIR_SEPARATOR);
285 #if defined(DIR_SEPARATOR_2)
286   const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2);
287   if (Sep2 && (!Sep || Sep2 > Sep))
288     Sep = Sep2;
289 #endif
290   return Sep;
291 }
292
293 COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
294 #if defined(__linux__)
295   int PDeachSig = 0;
296   /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
297   if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
298     prctl(PR_SET_PDEATHSIG, 0);
299   return (PDeachSig == SIGKILL);
300 #else
301   return 0;
302 #endif
303 }
304
305 COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
306 #if defined(__linux__)
307   prctl(PR_SET_PDEATHSIG, SIGKILL);
308 #endif
309 }