Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingUtil.c
35233 views
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
#if defined(__FreeBSD__)
42
#include <signal.h>
43
#include <sys/procctl.h>
44
#endif
45
46
#include "InstrProfiling.h"
47
#include "InstrProfilingUtil.h"
48
49
COMPILER_RT_VISIBILITY unsigned lprofDirMode = 0755;
50
51
COMPILER_RT_VISIBILITY
52
void __llvm_profile_recursive_mkdir(char *path) {
53
int i;
54
int start = 1;
55
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".
62
//
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;
69
}
70
#endif
71
72
for (i = start; path[i] != '\0'; ++i) {
73
char save = path[i];
74
if (!IS_DIR_SEPARATOR(path[i]))
75
continue;
76
path[i] = '\0';
77
#ifdef _WIN32
78
_mkdir(path);
79
#else
80
/* Some of these will fail, ignore it. */
81
mkdir(path, __llvm_profile_get_dir_mode());
82
#endif
83
path[i] = save;
84
}
85
}
86
87
COMPILER_RT_VISIBILITY
88
void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
89
90
COMPILER_RT_VISIBILITY
91
unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
92
93
#if COMPILER_RT_HAS_ATOMICS != 1
94
COMPILER_RT_VISIBILITY
95
uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
96
void *R = *Ptr;
97
if (R == OldV) {
98
*Ptr = NewV;
99
return 1;
100
}
101
return 0;
102
}
103
COMPILER_RT_VISIBILITY
104
void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
105
void *Old = *Mem;
106
*((char **)Mem) += ByteIncr;
107
return Old;
108
}
109
110
#endif
111
112
#ifdef _WIN32
113
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
114
WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
115
DWORD BufferSize = sizeof(Buffer);
116
BOOL Result =
117
GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
118
if (!Result)
119
return -1;
120
if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
121
return -1;
122
return 0;
123
}
124
#elif defined(COMPILER_RT_HAS_UNAME)
125
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
126
struct utsname N;
127
int R = uname(&N);
128
if (R >= 0) {
129
strncpy(Name, N.nodename, Len);
130
return 0;
131
}
132
return R;
133
}
134
#endif
135
136
COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
137
#ifdef COMPILER_RT_HAS_FCNTL_LCK
138
struct flock s_flock;
139
140
s_flock.l_whence = SEEK_SET;
141
s_flock.l_start = 0;
142
s_flock.l_len = 0; /* Until EOF. */
143
s_flock.l_pid = getpid();
144
s_flock.l_type = F_WRLCK;
145
146
while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
147
if (errno != EINTR) {
148
if (errno == ENOLCK) {
149
return -1;
150
}
151
break;
152
}
153
}
154
return 0;
155
#else
156
flock(fd, LOCK_EX);
157
return 0;
158
#endif
159
}
160
161
COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
162
#ifdef COMPILER_RT_HAS_FCNTL_LCK
163
struct flock s_flock;
164
165
s_flock.l_whence = SEEK_SET;
166
s_flock.l_start = 0;
167
s_flock.l_len = 0; /* Until EOF. */
168
s_flock.l_pid = getpid();
169
s_flock.l_type = F_UNLCK;
170
171
while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
172
if (errno != EINTR) {
173
if (errno == ENOLCK) {
174
return -1;
175
}
176
break;
177
}
178
}
179
return 0;
180
#else
181
flock(fd, LOCK_UN);
182
return 0;
183
#endif
184
}
185
186
COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {
187
int fd;
188
#if defined(_WIN32)
189
fd = _fileno(F);
190
#else
191
fd = fileno(F);
192
#endif
193
return lprofLockFd(fd);
194
}
195
196
COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {
197
int fd;
198
#if defined(_WIN32)
199
fd = _fileno(F);
200
#else
201
fd = fileno(F);
202
#endif
203
return lprofUnlockFd(fd);
204
}
205
206
COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
207
FILE *f;
208
int fd;
209
#ifdef COMPILER_RT_HAS_FCNTL_LCK
210
fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
211
if (fd < 0)
212
return NULL;
213
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.");
217
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)
225
return NULL;
226
227
fd = _open_osfhandle((intptr_t)h, 0);
228
if (fd == -1) {
229
CloseHandle(h);
230
return NULL;
231
}
232
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.");
236
237
f = _fdopen(fd, "r+b");
238
if (f == 0) {
239
CloseHandle(h);
240
return NULL;
241
}
242
#else
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);
247
if (fd < 0)
248
return NULL;
249
f = fdopen(fd, "r+b");
250
#endif
251
252
return f;
253
}
254
255
COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
256
size_t *PrefixLen) {
257
const char *Prefix = getenv("GCOV_PREFIX");
258
const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
259
260
*PrefixLen = 0;
261
*PrefixStrip = 0;
262
if (Prefix == NULL || Prefix[0] == '\0')
263
return NULL;
264
265
if (PrefixStripStr) {
266
*PrefixStrip = atoi(PrefixStripStr);
267
268
/* Negative GCOV_PREFIX_STRIP values are ignored */
269
if (*PrefixStrip < 0)
270
*PrefixStrip = 0;
271
} else {
272
*PrefixStrip = 0;
273
}
274
*PrefixLen = strlen(Prefix);
275
276
return Prefix;
277
}
278
279
COMPILER_RT_VISIBILITY void
280
lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
281
size_t PrefixLen, int PrefixStrip) {
282
283
const char *Ptr;
284
int Level;
285
const char *StrippedPathStr = PathStr;
286
287
for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
288
if (*Ptr == '\0')
289
break;
290
291
if (!IS_DIR_SEPARATOR(*Ptr))
292
continue;
293
294
StrippedPathStr = Ptr;
295
++Level;
296
}
297
298
memcpy(Dest, Prefix, PrefixLen);
299
300
if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
301
Dest[PrefixLen++] = DIR_SEPARATOR;
302
303
memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
304
}
305
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))
312
Sep = Sep2;
313
#endif
314
return Sep;
315
}
316
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))
322
Sep = Sep2;
323
#endif
324
return Sep;
325
}
326
327
COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) {
328
#if defined(__linux__)
329
int PDeachSig = 0;
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);
340
#else
341
return 0;
342
#endif
343
}
344
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);
351
#endif
352
}
353
354
COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,
355
uintptr_t End) {
356
#if defined(__ve__)
357
// VE doesn't support madvise.
358
return 0;
359
#else
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);
368
#else
369
return madvise((void *)BeginAligned, EndAligned - BeginAligned,
370
MADV_DONTNEED);
371
#endif
372
}
373
return 0;
374
#endif
375
}
376
377