]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/profile/InstrProfilingUtil.c
Merge ^/head r327624 through r327885.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / profile / InstrProfilingUtil.c
1 /*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
2 |*
3 |*                     The LLVM Compiler Infrastructure
4 |*
5 |* This file is distributed under the University of Illinois Open Source
6 |* License. See LICENSE.TXT for details.
7 |*
8 \*===----------------------------------------------------------------------===*/
9
10 #ifdef _WIN32
11 #include <direct.h>
12 #include <process.h>
13 #include <windows.h>
14 #include "WindowsMMap.h"
15 #else
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
38 COMPILER_RT_VISIBILITY
39 void __llvm_profile_recursive_mkdir(char *path) {
40   int i;
41
42   for (i = 1; path[i] != '\0'; ++i) {
43     char save = path[i];
44     if (!IS_DIR_SEPARATOR(path[i]))
45       continue;
46     path[i] = '\0';
47 #ifdef _WIN32
48     _mkdir(path);
49 #else
50     mkdir(path, 0755); /* Some of these will fail, ignore it. */
51 #endif
52     path[i] = save;
53   }
54 }
55
56 #if COMPILER_RT_HAS_ATOMICS != 1
57 COMPILER_RT_VISIBILITY
58 uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
59   void *R = *Ptr;
60   if (R == OldV) {
61     *Ptr = NewV;
62     return 1;
63   }
64   return 0;
65 }
66 COMPILER_RT_VISIBILITY
67 void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
68   void *Old = *Mem;
69   *((char **)Mem) += ByteIncr;
70   return Old;
71 }
72
73 #endif
74
75 #ifdef _MSC_VER
76 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
77   WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
78   DWORD BufferSize = sizeof(Buffer);
79   BOOL Result =
80       GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
81   if (!Result)
82     return -1;
83   if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
84     return -1;
85   return 0;
86 }
87 #elif defined(COMPILER_RT_HAS_UNAME)
88 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
89   struct utsname N;
90   int R = uname(&N);
91   if (R >= 0) {
92     strncpy(Name, N.nodename, Len);
93     return 0;
94   }
95   return R;
96 }
97 #endif
98
99 COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
100 #ifdef COMPILER_RT_HAS_FCNTL_LCK
101   struct flock s_flock;
102
103   s_flock.l_whence = SEEK_SET;
104   s_flock.l_start = 0;
105   s_flock.l_len = 0; /* Until EOF.  */
106   s_flock.l_pid = getpid();
107   s_flock.l_type = F_WRLCK;
108
109   while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
110     if (errno != EINTR) {
111       if (errno == ENOLCK) {
112         return -1;
113       }
114       break;
115     }
116   }
117   return 0;
118 #else
119   flock(fd, LOCK_EX);
120   return 0;
121 #endif
122 }
123
124 COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
125 #ifdef COMPILER_RT_HAS_FCNTL_LCK
126   struct flock s_flock;
127
128   s_flock.l_whence = SEEK_SET;
129   s_flock.l_start = 0;
130   s_flock.l_len = 0; /* Until EOF.  */
131   s_flock.l_pid = getpid();
132   s_flock.l_type = F_UNLCK;
133
134   while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
135     if (errno != EINTR) {
136       if (errno == ENOLCK) {
137         return -1;
138       }
139       break;
140     }
141   }
142   return 0;
143 #else
144   flock(fd, LOCK_UN);
145   return 0;
146 #endif
147 }
148
149 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
150   FILE *f;
151   int fd;
152 #ifdef COMPILER_RT_HAS_FCNTL_LCK
153   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
154   if (fd < 0)
155     return NULL;
156
157   if (lprofLockFd(fd) != 0)
158     PROF_WARN("Data may be corrupted during profile merging : %s\n",
159               "Fail to obtain file lock due to system limit.");
160
161   f = fdopen(fd, "r+b");
162 #elif defined(_WIN32)
163   // FIXME: Use the wide variants to handle Unicode filenames.
164   HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
165                          OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
166   if (h == INVALID_HANDLE_VALUE)
167     return NULL;
168
169   fd = _open_osfhandle((intptr_t)h, 0);
170   if (fd == -1) {
171     CloseHandle(h);
172     return NULL;
173   }
174
175   f = _fdopen(fd, "r+b");
176   if (f == 0) {
177     CloseHandle(h);
178     return NULL;
179   }
180 #else
181   /* Worst case no locking applied.  */
182   PROF_WARN("Concurrent file access is not supported : %s\n",
183             "lack file locking");
184   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
185   if (fd < 0)
186     return NULL;
187   f = fdopen(fd, "r+b");
188 #endif
189
190   return f;
191 }
192
193 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
194                                                       size_t *PrefixLen) {
195   const char *Prefix = getenv("GCOV_PREFIX");
196   const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
197
198   *PrefixLen = 0;
199   *PrefixStrip = 0;
200   if (Prefix == NULL || Prefix[0] == '\0')
201     return NULL;
202
203   if (PrefixStripStr) {
204     *PrefixStrip = atoi(PrefixStripStr);
205
206     /* Negative GCOV_PREFIX_STRIP values are ignored */
207     if (*PrefixStrip < 0)
208       *PrefixStrip = 0;
209   } else {
210     *PrefixStrip = 0;
211   }
212   *PrefixLen = strlen(Prefix);
213
214   return Prefix;
215 }
216
217 COMPILER_RT_VISIBILITY void
218 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
219                      size_t PrefixLen, int PrefixStrip) {
220
221   const char *Ptr;
222   int Level;
223   const char *StrippedPathStr = PathStr;
224
225   for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
226     if (*Ptr == '\0')
227       break;
228
229     if (!IS_DIR_SEPARATOR(*Ptr))
230       continue;
231
232     StrippedPathStr = Ptr;
233     ++Level;
234   }
235
236   memcpy(Dest, Prefix, PrefixLen);
237
238   if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
239     Dest[PrefixLen++] = DIR_SEPARATOR;
240
241   memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
242 }
243
244 COMPILER_RT_VISIBILITY const char *
245 lprofFindFirstDirSeparator(const char *Path) {
246   const char *Sep;
247   Sep = strchr(Path, DIR_SEPARATOR);
248   if (Sep)
249     return Sep;
250 #if defined(DIR_SEPARATOR_2)
251   Sep = strchr(Path, DIR_SEPARATOR_2);
252 #endif
253   return Sep;
254 }
255
256 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
257   const char *Sep;
258   Sep = strrchr(Path, DIR_SEPARATOR);
259   if (Sep)
260     return Sep;
261 #if defined(DIR_SEPARATOR_2)
262   Sep = strrchr(Path, DIR_SEPARATOR_2);
263 #endif
264   return Sep;
265 }
266
267 COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
268 #if defined(__linux__)
269   int PDeachSig = 0;
270   /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
271   if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
272     prctl(PR_SET_PDEATHSIG, 0);
273   return (PDeachSig == SIGKILL);
274 #else
275   return 0;
276 #endif
277 }
278
279 COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
280 #if defined(__linux__)
281   prctl(PR_SET_PDEATHSIG, SIGKILL);
282 #endif
283 }