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