1 /*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
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
7 \*===----------------------------------------------------------------------===*/
13 #include "WindowsMMap.h"
20 #include <sys/types.h>
24 #ifdef COMPILER_RT_HAS_UNAME
25 #include <sys/utsname.h>
31 #if defined(__linux__)
33 #include <sys/prctl.h>
36 #if defined(__Fuchsia__)
37 #include <zircon/process.h>
38 #include <zircon/syscalls.h>
41 #if defined(__FreeBSD__)
43 #include <sys/procctl.h>
46 #include "InstrProfiling.h"
47 #include "InstrProfilingUtil.h"
49 COMPILER_RT_VISIBILITY
unsigned lprofDirMode
= 0755;
51 COMPILER_RT_VISIBILITY
52 void __llvm_profile_recursive_mkdir(char *path
) {
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".
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
;
72 for (i
= start
; path
[i
] != '\0'; ++i
) {
74 if (!IS_DIR_SEPARATOR(path
[i
]))
80 /* Some of these will fail, ignore it. */
81 mkdir(path
, __llvm_profile_get_dir_mode());
87 COMPILER_RT_VISIBILITY
88 void __llvm_profile_set_dir_mode(unsigned Mode
) { lprofDirMode
= Mode
; }
90 COMPILER_RT_VISIBILITY
91 unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode
; }
93 #if COMPILER_RT_HAS_ATOMICS != 1
94 COMPILER_RT_VISIBILITY
95 uint32_t lprofBoolCmpXchg(void **Ptr
, void *OldV
, void *NewV
) {
103 COMPILER_RT_VISIBILITY
104 void *lprofPtrFetchAdd(void **Mem
, long ByteIncr
) {
106 *((char **)Mem
) += ByteIncr
;
113 COMPILER_RT_VISIBILITY
int lprofGetHostName(char *Name
, int Len
) {
114 WCHAR Buffer
[COMPILER_RT_MAX_HOSTLEN
];
115 DWORD BufferSize
= sizeof(Buffer
);
117 GetComputerNameExW(ComputerNameDnsFullyQualified
, Buffer
, &BufferSize
);
120 if (WideCharToMultiByte(CP_UTF8
, 0, Buffer
, -1, Name
, Len
, NULL
, NULL
) == 0)
124 #elif defined(COMPILER_RT_HAS_UNAME)
125 COMPILER_RT_VISIBILITY
int lprofGetHostName(char *Name
, int Len
) {
129 strncpy(Name
, N
.nodename
, Len
);
136 COMPILER_RT_VISIBILITY
int lprofLockFd(int fd
) {
137 #ifdef COMPILER_RT_HAS_FCNTL_LCK
138 struct flock s_flock
;
140 s_flock
.l_whence
= SEEK_SET
;
142 s_flock
.l_len
= 0; /* Until EOF. */
143 s_flock
.l_pid
= getpid();
144 s_flock
.l_type
= F_WRLCK
;
146 while (fcntl(fd
, F_SETLKW
, &s_flock
) == -1) {
147 if (errno
!= EINTR
) {
148 if (errno
== ENOLCK
) {
161 COMPILER_RT_VISIBILITY
int lprofUnlockFd(int fd
) {
162 #ifdef COMPILER_RT_HAS_FCNTL_LCK
163 struct flock s_flock
;
165 s_flock
.l_whence
= SEEK_SET
;
167 s_flock
.l_len
= 0; /* Until EOF. */
168 s_flock
.l_pid
= getpid();
169 s_flock
.l_type
= F_UNLCK
;
171 while (fcntl(fd
, F_SETLKW
, &s_flock
) == -1) {
172 if (errno
!= EINTR
) {
173 if (errno
== ENOLCK
) {
186 COMPILER_RT_VISIBILITY
int lprofLockFileHandle(FILE *F
) {
193 return lprofLockFd(fd
);
196 COMPILER_RT_VISIBILITY
int lprofUnlockFileHandle(FILE *F
) {
203 return lprofUnlockFd(fd
);
206 COMPILER_RT_VISIBILITY
FILE *lprofOpenFileEx(const char *ProfileName
) {
209 #ifdef COMPILER_RT_HAS_FCNTL_LCK
210 fd
= open(ProfileName
, O_RDWR
| O_CREAT
, 0666);
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.");
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
)
227 fd
= _open_osfhandle((intptr_t)h
, 0);
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.");
237 f
= _fdopen(fd
, "r+b");
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);
249 f
= fdopen(fd
, "r+b");
255 COMPILER_RT_VISIBILITY
const char *lprofGetPathPrefix(int *PrefixStrip
,
257 const char *Prefix
= getenv("GCOV_PREFIX");
258 const char *PrefixStripStr
= getenv("GCOV_PREFIX_STRIP");
262 if (Prefix
== NULL
|| Prefix
[0] == '\0')
265 if (PrefixStripStr
) {
266 *PrefixStrip
= atoi(PrefixStripStr
);
268 /* Negative GCOV_PREFIX_STRIP values are ignored */
269 if (*PrefixStrip
< 0)
274 *PrefixLen
= strlen(Prefix
);
279 COMPILER_RT_VISIBILITY
void
280 lprofApplyPathPrefix(char *Dest
, const char *PathStr
, const char *Prefix
,
281 size_t PrefixLen
, int PrefixStrip
) {
285 const char *StrippedPathStr
= PathStr
;
287 for (Level
= 0, Ptr
= PathStr
+ 1; Level
< PrefixStrip
; ++Ptr
) {
291 if (!IS_DIR_SEPARATOR(*Ptr
))
294 StrippedPathStr
= Ptr
;
298 memcpy(Dest
, Prefix
, PrefixLen
);
300 if (!IS_DIR_SEPARATOR(Prefix
[PrefixLen
- 1]))
301 Dest
[PrefixLen
++] = DIR_SEPARATOR
;
303 memcpy(Dest
+ PrefixLen
, StrippedPathStr
, strlen(StrippedPathStr
) + 1);
306 COMPILER_RT_VISIBILITY
const char *
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
))
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
))
327 COMPILER_RT_VISIBILITY
int lprofSuspendSigKill(void) {
328 #if defined(__linux__)
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
);
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
);
354 COMPILER_RT_VISIBILITY
int lprofReleaseMemoryPagesToOS(uintptr_t Begin
,
357 // VE doesn't support madvise.
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);
369 return madvise((void *)BeginAligned
, EndAligned
- BeginAligned
,