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