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 <errno.h>
16 #include <fcntl.h>
17 #include <sys/file.h>
18 #include <sys/mman.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #endif
23
24 #ifdef COMPILER_RT_HAS_UNAME
25 #include <sys/utsname.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #if defined(__linux__)
32 #include <signal.h>
33 #include <sys/prctl.h>
34 #endif
35
36 #if defined(__Fuchsia__)
37 #include <zircon/process.h>
38 #include <zircon/syscalls.h>
39 #endif
40
41 #if defined(__FreeBSD__)
42 #include <signal.h>
43 #include <sys/procctl.h>
44 #endif
45
46 #include "InstrProfiling.h"
47 #include "InstrProfilingUtil.h"
48
49 COMPILER_RT_VISIBILITY unsigned lprofDirMode = 0755;
50
51 COMPILER_RT_VISIBILITY
__llvm_profile_recursive_mkdir(char * path)52 void __llvm_profile_recursive_mkdir(char *path) {
53 int i;
54 int start = 1;
55
56 #if defined(__ANDROID__) && defined(__ANDROID_API__) && \
57 defined(__ANDROID_API_FUTURE__) && \
58 __ANDROID_API__ == __ANDROID_API_FUTURE__
59 // Avoid spammy selinux denial messages in Android by not attempting to
60 // create directories in GCOV_PREFIX. These denials occur when creating (or
61 // even attempting to stat()) top-level directories like "/data".
62 //
63 // Do so by ignoring ${GCOV_PREFIX} when invoking mkdir().
64 const char *gcov_prefix = getenv("GCOV_PREFIX");
65 if (gcov_prefix != NULL) {
66 const int gcov_prefix_len = strlen(gcov_prefix);
67 if (strncmp(path, gcov_prefix, gcov_prefix_len) == 0)
68 start = gcov_prefix_len;
69 }
70 #endif
71
72 for (i = start; path[i] != '\0'; ++i) {
73 char save = path[i];
74 if (!IS_DIR_SEPARATOR(path[i]))
75 continue;
76 path[i] = '\0';
77 #ifdef _WIN32
78 _mkdir(path);
79 #else
80 /* Some of these will fail, ignore it. */
81 mkdir(path, __llvm_profile_get_dir_mode());
82 #endif
83 path[i] = save;
84 }
85 }
86
87 COMPILER_RT_VISIBILITY
__llvm_profile_set_dir_mode(unsigned Mode)88 void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
89
90 COMPILER_RT_VISIBILITY
__llvm_profile_get_dir_mode(void)91 unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
92
93 #if COMPILER_RT_HAS_ATOMICS != 1
94 COMPILER_RT_VISIBILITY
lprofBoolCmpXchg(void ** Ptr,void * OldV,void * NewV)95 uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
96 void *R = *Ptr;
97 if (R == OldV) {
98 *Ptr = NewV;
99 return 1;
100 }
101 return 0;
102 }
103 COMPILER_RT_VISIBILITY
lprofPtrFetchAdd(void ** Mem,long ByteIncr)104 void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
105 void *Old = *Mem;
106 *((char **)Mem) += ByteIncr;
107 return Old;
108 }
109
110 #endif
111
112 #ifdef _WIN32
lprofGetHostName(char * Name,int Len)113 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
114 WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
115 DWORD BufferSize = sizeof(Buffer);
116 BOOL Result =
117 GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
118 if (!Result)
119 return -1;
120 if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
121 return -1;
122 return 0;
123 }
124 #elif defined(COMPILER_RT_HAS_UNAME)
lprofGetHostName(char * Name,int Len)125 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
126 struct utsname N;
127 int R = uname(&N);
128 if (R >= 0) {
129 strncpy(Name, N.nodename, Len);
130 return 0;
131 }
132 return R;
133 }
134 #endif
135
lprofLockFd(int fd)136 COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
137 #ifdef COMPILER_RT_HAS_FCNTL_LCK
138 struct flock s_flock;
139
140 s_flock.l_whence = SEEK_SET;
141 s_flock.l_start = 0;
142 s_flock.l_len = 0; /* Until EOF. */
143 s_flock.l_pid = getpid();
144 s_flock.l_type = F_WRLCK;
145
146 while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
147 if (errno != EINTR) {
148 if (errno == ENOLCK) {
149 return -1;
150 }
151 break;
152 }
153 }
154 return 0;
155 #else
156 flock(fd, LOCK_EX);
157 return 0;
158 #endif
159 }
160
lprofUnlockFd(int fd)161 COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
162 #ifdef COMPILER_RT_HAS_FCNTL_LCK
163 struct flock s_flock;
164
165 s_flock.l_whence = SEEK_SET;
166 s_flock.l_start = 0;
167 s_flock.l_len = 0; /* Until EOF. */
168 s_flock.l_pid = getpid();
169 s_flock.l_type = F_UNLCK;
170
171 while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
172 if (errno != EINTR) {
173 if (errno == ENOLCK) {
174 return -1;
175 }
176 break;
177 }
178 }
179 return 0;
180 #else
181 flock(fd, LOCK_UN);
182 return 0;
183 #endif
184 }
185
lprofLockFileHandle(FILE * F)186 COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {
187 int fd;
188 #if defined(_WIN32)
189 fd = _fileno(F);
190 #else
191 fd = fileno(F);
192 #endif
193 return lprofLockFd(fd);
194 }
195
lprofUnlockFileHandle(FILE * F)196 COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {
197 int fd;
198 #if defined(_WIN32)
199 fd = _fileno(F);
200 #else
201 fd = fileno(F);
202 #endif
203 return lprofUnlockFd(fd);
204 }
205
lprofOpenFileEx(const char * ProfileName)206 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
207 FILE *f;
208 int fd;
209 #ifdef COMPILER_RT_HAS_FCNTL_LCK
210 fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
211 if (fd < 0)
212 return NULL;
213
214 if (lprofLockFd(fd) != 0)
215 PROF_WARN("Data may be corrupted during profile merging : %s\n",
216 "Fail to obtain file lock due to system limit.");
217
218 f = fdopen(fd, "r+b");
219 #elif defined(_WIN32)
220 // FIXME: Use the wide variants to handle Unicode filenames.
221 HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE,
222 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
223 FILE_ATTRIBUTE_NORMAL, 0);
224 if (h == INVALID_HANDLE_VALUE)
225 return NULL;
226
227 fd = _open_osfhandle((intptr_t)h, 0);
228 if (fd == -1) {
229 CloseHandle(h);
230 return NULL;
231 }
232
233 if (lprofLockFd(fd) != 0)
234 PROF_WARN("Data may be corrupted during profile merging : %s\n",
235 "Fail to obtain file lock due to system limit.");
236
237 f = _fdopen(fd, "r+b");
238 if (f == 0) {
239 CloseHandle(h);
240 return NULL;
241 }
242 #else
243 /* Worst case no locking applied. */
244 PROF_WARN("Concurrent file access is not supported : %s\n",
245 "lack file locking");
246 fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
247 if (fd < 0)
248 return NULL;
249 f = fdopen(fd, "r+b");
250 #endif
251
252 return f;
253 }
254
lprofGetPathPrefix(int * PrefixStrip,size_t * PrefixLen)255 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
256 size_t *PrefixLen) {
257 const char *Prefix = getenv("GCOV_PREFIX");
258 const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
259
260 *PrefixLen = 0;
261 *PrefixStrip = 0;
262 if (Prefix == NULL || Prefix[0] == '\0')
263 return NULL;
264
265 if (PrefixStripStr) {
266 *PrefixStrip = atoi(PrefixStripStr);
267
268 /* Negative GCOV_PREFIX_STRIP values are ignored */
269 if (*PrefixStrip < 0)
270 *PrefixStrip = 0;
271 } else {
272 *PrefixStrip = 0;
273 }
274 *PrefixLen = strlen(Prefix);
275
276 return Prefix;
277 }
278
279 COMPILER_RT_VISIBILITY void
lprofApplyPathPrefix(char * Dest,const char * PathStr,const char * Prefix,size_t PrefixLen,int PrefixStrip)280 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
281 size_t PrefixLen, int PrefixStrip) {
282
283 const char *Ptr;
284 int Level;
285 const char *StrippedPathStr = PathStr;
286
287 for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
288 if (*Ptr == '\0')
289 break;
290
291 if (!IS_DIR_SEPARATOR(*Ptr))
292 continue;
293
294 StrippedPathStr = Ptr;
295 ++Level;
296 }
297
298 memcpy(Dest, Prefix, PrefixLen);
299
300 if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
301 Dest[PrefixLen++] = DIR_SEPARATOR;
302
303 memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
304 }
305
306 COMPILER_RT_VISIBILITY const char *
lprofFindFirstDirSeparator(const char * Path)307 lprofFindFirstDirSeparator(const char *Path) {
308 const char *Sep = strchr(Path, DIR_SEPARATOR);
309 #if defined(DIR_SEPARATOR_2)
310 const char *Sep2 = strchr(Path, DIR_SEPARATOR_2);
311 if (Sep2 && (!Sep || Sep2 < Sep))
312 Sep = Sep2;
313 #endif
314 return Sep;
315 }
316
lprofFindLastDirSeparator(const char * Path)317 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
318 const char *Sep = strrchr(Path, DIR_SEPARATOR);
319 #if defined(DIR_SEPARATOR_2)
320 const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2);
321 if (Sep2 && (!Sep || Sep2 > Sep))
322 Sep = Sep2;
323 #endif
324 return Sep;
325 }
326
lprofSuspendSigKill(void)327 COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) {
328 #if defined(__linux__)
329 int PDeachSig = 0;
330 /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
331 if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
332 prctl(PR_SET_PDEATHSIG, 0);
333 return (PDeachSig == SIGKILL);
334 #elif defined(__FreeBSD__)
335 int PDeachSig = 0, PDisableSig = 0;
336 if (procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &PDeachSig) == 0 &&
337 PDeachSig == SIGKILL)
338 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PDisableSig);
339 return (PDeachSig == SIGKILL);
340 #else
341 return 0;
342 #endif
343 }
344
lprofRestoreSigKill(void)345 COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) {
346 #if defined(__linux__)
347 prctl(PR_SET_PDEATHSIG, SIGKILL);
348 #elif defined(__FreeBSD__)
349 int PEnableSig = SIGKILL;
350 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PEnableSig);
351 #endif
352 }
353
lprofReleaseMemoryPagesToOS(uintptr_t Begin,uintptr_t End)354 COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,
355 uintptr_t End) {
356 #if defined(__ve__)
357 // VE doesn't support madvise.
358 return 0;
359 #else
360 size_t PageSize = getpagesize();
361 uintptr_t BeginAligned = lprofRoundUpTo((uintptr_t)Begin, PageSize);
362 uintptr_t EndAligned = lprofRoundDownTo((uintptr_t)End, PageSize);
363 if (BeginAligned < EndAligned) {
364 #if defined(__Fuchsia__)
365 return _zx_vmar_op_range(_zx_vmar_root_self(), ZX_VMAR_OP_DECOMMIT,
366 (zx_vaddr_t)BeginAligned,
367 EndAligned - BeginAligned, NULL, 0);
368 #else
369 return madvise((void *)BeginAligned, EndAligned - BeginAligned,
370 MADV_DONTNEED);
371 #endif
372 }
373 return 0;
374 #endif
375 }
376