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"
16 #include <sys/types.h>
22 #ifdef COMPILER_RT_HAS_UNAME
23 #include <sys/utsname.h>
29 #if defined(__linux__)
31 #include <sys/prctl.h>
34 #include "InstrProfiling.h"
35 #include "InstrProfilingUtil.h"
37 COMPILER_RT_WEAK unsigned lprofDirMode = 0755;
39 COMPILER_RT_VISIBILITY
40 void __llvm_profile_recursive_mkdir(char *path) {
43 for (i = 1; path[i] != '\0'; ++i) {
45 if (!IS_DIR_SEPARATOR(path[i]))
51 /* Some of these will fail, ignore it. */
52 mkdir(path, __llvm_profile_get_dir_mode());
58 COMPILER_RT_VISIBILITY
59 void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
61 COMPILER_RT_VISIBILITY
62 unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
64 #if COMPILER_RT_HAS_ATOMICS != 1
65 COMPILER_RT_VISIBILITY
66 uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
74 COMPILER_RT_VISIBILITY
75 void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
77 *((char **)Mem) += ByteIncr;
84 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
85 WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
86 DWORD BufferSize = sizeof(Buffer);
88 GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
91 if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
95 #elif defined(COMPILER_RT_HAS_UNAME)
96 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
100 strncpy(Name, N.nodename, Len);
107 COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
108 #ifdef COMPILER_RT_HAS_FCNTL_LCK
109 struct flock s_flock;
111 s_flock.l_whence = SEEK_SET;
113 s_flock.l_len = 0; /* Until EOF. */
114 s_flock.l_pid = getpid();
115 s_flock.l_type = F_WRLCK;
117 while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
118 if (errno != EINTR) {
119 if (errno == ENOLCK) {
132 COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
133 #ifdef COMPILER_RT_HAS_FCNTL_LCK
134 struct flock s_flock;
136 s_flock.l_whence = SEEK_SET;
138 s_flock.l_len = 0; /* Until EOF. */
139 s_flock.l_pid = getpid();
140 s_flock.l_type = F_UNLCK;
142 while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
143 if (errno != EINTR) {
144 if (errno == ENOLCK) {
157 COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {
164 return lprofLockFd(fd);
167 COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {
174 return lprofUnlockFd(fd);
177 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
180 #ifdef COMPILER_RT_HAS_FCNTL_LCK
181 fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
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.");
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)
198 fd = _open_osfhandle((intptr_t)h, 0);
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.");
208 f = _fdopen(fd, "r+b");
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);
220 f = fdopen(fd, "r+b");
226 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
228 const char *Prefix = getenv("GCOV_PREFIX");
229 const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
233 if (Prefix == NULL || Prefix[0] == '\0')
236 if (PrefixStripStr) {
237 *PrefixStrip = atoi(PrefixStripStr);
239 /* Negative GCOV_PREFIX_STRIP values are ignored */
240 if (*PrefixStrip < 0)
245 *PrefixLen = strlen(Prefix);
250 COMPILER_RT_VISIBILITY void
251 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
252 size_t PrefixLen, int PrefixStrip) {
256 const char *StrippedPathStr = PathStr;
258 for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
262 if (!IS_DIR_SEPARATOR(*Ptr))
265 StrippedPathStr = Ptr;
269 memcpy(Dest, Prefix, PrefixLen);
271 if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
272 Dest[PrefixLen++] = DIR_SEPARATOR;
274 memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
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))
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))
298 COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
299 #if defined(__linux__)
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);
310 COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
311 #if defined(__linux__)
312 prctl(PR_SET_PDEATHSIG, SIGKILL);