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 #elif defined(COMPILER_RT_HAS_FLOCK) || defined(_WIN32) 156 // Windows doesn't have flock but WindowsMMap.h provides a shim 157 flock(fd, LOCK_EX); 158 return 0; 159 #else 160 return 0; 161 #endif 162 } 163 164 COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) { 165 #ifdef COMPILER_RT_HAS_FCNTL_LCK 166 struct flock s_flock; 167 168 s_flock.l_whence = SEEK_SET; 169 s_flock.l_start = 0; 170 s_flock.l_len = 0; /* Until EOF. */ 171 s_flock.l_pid = getpid(); 172 s_flock.l_type = F_UNLCK; 173 174 while (fcntl(fd, F_SETLKW, &s_flock) == -1) { 175 if (errno != EINTR) { 176 if (errno == ENOLCK) { 177 return -1; 178 } 179 break; 180 } 181 } 182 return 0; 183 #elif defined(COMPILER_RT_HAS_FLOCK) || defined(_WIN32) 184 // Windows doesn't have flock but WindowsMMap.h provides a shim 185 flock(fd, LOCK_UN); 186 return 0; 187 #else 188 return 0; 189 #endif 190 } 191 192 COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) { 193 int fd; 194 #if defined(_WIN32) 195 fd = _fileno(F); 196 #else 197 fd = fileno(F); 198 #endif 199 return lprofLockFd(fd); 200 } 201 202 COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) { 203 int fd; 204 #if defined(_WIN32) 205 fd = _fileno(F); 206 #else 207 fd = fileno(F); 208 #endif 209 return lprofUnlockFd(fd); 210 } 211 212 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) { 213 FILE *f; 214 int fd; 215 #ifdef COMPILER_RT_HAS_FCNTL_LCK 216 fd = open(ProfileName, O_RDWR | O_CREAT, 0666); 217 if (fd < 0) 218 return NULL; 219 220 if (lprofLockFd(fd) != 0) 221 PROF_WARN("Data may be corrupted during profile merging : %s\n", 222 "Fail to obtain file lock due to system limit."); 223 224 f = fdopen(fd, "r+b"); 225 #elif defined(_WIN32) 226 // FIXME: Use the wide variants to handle Unicode filenames. 227 HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 228 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 229 FILE_ATTRIBUTE_NORMAL, 0); 230 if (h == INVALID_HANDLE_VALUE) 231 return NULL; 232 233 fd = _open_osfhandle((intptr_t)h, 0); 234 if (fd == -1) { 235 CloseHandle(h); 236 return NULL; 237 } 238 239 if (lprofLockFd(fd) != 0) 240 PROF_WARN("Data may be corrupted during profile merging : %s\n", 241 "Fail to obtain file lock due to system limit."); 242 243 f = _fdopen(fd, "r+b"); 244 if (f == 0) { 245 CloseHandle(h); 246 return NULL; 247 } 248 #else 249 /* Worst case no locking applied. */ 250 PROF_WARN("Concurrent file access is not supported : %s\n", 251 "lack file locking"); 252 fd = open(ProfileName, O_RDWR | O_CREAT, 0666); 253 if (fd < 0) 254 return NULL; 255 f = fdopen(fd, "r+b"); 256 #endif 257 258 return f; 259 } 260 261 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip, 262 size_t *PrefixLen) { 263 const char *Prefix = getenv("GCOV_PREFIX"); 264 const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP"); 265 266 *PrefixLen = 0; 267 *PrefixStrip = 0; 268 if (Prefix == NULL || Prefix[0] == '\0') 269 return NULL; 270 271 if (PrefixStripStr) { 272 *PrefixStrip = atoi(PrefixStripStr); 273 274 /* Negative GCOV_PREFIX_STRIP values are ignored */ 275 if (*PrefixStrip < 0) 276 *PrefixStrip = 0; 277 } else { 278 *PrefixStrip = 0; 279 } 280 *PrefixLen = strlen(Prefix); 281 282 return Prefix; 283 } 284 285 COMPILER_RT_VISIBILITY void 286 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix, 287 size_t PrefixLen, int PrefixStrip) { 288 289 const char *Ptr; 290 int Level; 291 const char *StrippedPathStr = PathStr; 292 293 for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) { 294 if (*Ptr == '\0') 295 break; 296 297 if (!IS_DIR_SEPARATOR(*Ptr)) 298 continue; 299 300 StrippedPathStr = Ptr; 301 ++Level; 302 } 303 304 memcpy(Dest, Prefix, PrefixLen); 305 306 if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1])) 307 Dest[PrefixLen++] = DIR_SEPARATOR; 308 309 memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1); 310 } 311 312 COMPILER_RT_VISIBILITY const char * 313 lprofFindFirstDirSeparator(const char *Path) { 314 const char *Sep = strchr(Path, DIR_SEPARATOR); 315 #if defined(DIR_SEPARATOR_2) 316 const char *Sep2 = strchr(Path, DIR_SEPARATOR_2); 317 if (Sep2 && (!Sep || Sep2 < Sep)) 318 Sep = Sep2; 319 #endif 320 return Sep; 321 } 322 323 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) { 324 const char *Sep = strrchr(Path, DIR_SEPARATOR); 325 #if defined(DIR_SEPARATOR_2) 326 const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2); 327 if (Sep2 && (!Sep || Sep2 > Sep)) 328 Sep = Sep2; 329 #endif 330 return Sep; 331 } 332 333 COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) { 334 #if defined(__linux__) 335 int PDeachSig = 0; 336 /* Temporarily suspend getting SIGKILL upon exit of the parent process. */ 337 if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL) 338 prctl(PR_SET_PDEATHSIG, 0); 339 return (PDeachSig == SIGKILL); 340 #elif defined(__FreeBSD__) 341 int PDeachSig = 0, PDisableSig = 0; 342 if (procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &PDeachSig) == 0 && 343 PDeachSig == SIGKILL) 344 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PDisableSig); 345 return (PDeachSig == SIGKILL); 346 #else 347 return 0; 348 #endif 349 } 350 351 COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) { 352 #if defined(__linux__) 353 prctl(PR_SET_PDEATHSIG, SIGKILL); 354 #elif defined(__FreeBSD__) 355 int PEnableSig = SIGKILL; 356 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PEnableSig); 357 #endif 358 } 359 360 COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin, 361 uintptr_t End) { 362 #if defined(__ve__) || defined(__wasi__) 363 // VE and WASI doesn't support madvise. 364 return 0; 365 #else 366 size_t PageSize = getpagesize(); 367 uintptr_t BeginAligned = lprofRoundUpTo((uintptr_t)Begin, PageSize); 368 uintptr_t EndAligned = lprofRoundDownTo((uintptr_t)End, PageSize); 369 if (BeginAligned < EndAligned) { 370 #if defined(__Fuchsia__) 371 return _zx_vmar_op_range(_zx_vmar_root_self(), ZX_VMAR_OP_DECOMMIT, 372 (zx_vaddr_t)BeginAligned, 373 EndAligned - BeginAligned, NULL, 0); 374 #else 375 return madvise((void *)BeginAligned, EndAligned - BeginAligned, 376 MADV_DONTNEED); 377 #endif 378 } 379 return 0; 380 #endif 381 } 382 383 #ifdef _AIX 384 typedef struct fn_node { 385 AtExit_Fn_ptr func; 386 struct fn_node *next; 387 } fn_node; 388 typedef struct { 389 fn_node *top; 390 } fn_stack; 391 392 static void fn_stack_push(fn_stack *, AtExit_Fn_ptr); 393 static AtExit_Fn_ptr fn_stack_pop(fn_stack *); 394 /* return 1 if stack is empty, 0 otherwise */ 395 static int fn_stack_is_empty(fn_stack *); 396 397 static fn_stack AtExit_stack = {0}; 398 #define ATEXIT_STACK (&AtExit_stack) 399 400 /* On AIX, atexit() functions registered by a shared library do not get called 401 * when the library is dlclose'd, causing a crash when they are eventually 402 * called at main program exit. However, a destructor does get called. So we 403 * collect all atexit functions registered by profile-rt and at program 404 * termination time (normal exit, shared library unload, or dlclose) we walk 405 * the list and execute any function that is still sitting in the atexit system 406 * queue. 407 */ 408 __attribute__((__destructor__)) static void cleanup() { 409 while (!fn_stack_is_empty(ATEXIT_STACK)) { 410 AtExit_Fn_ptr func = fn_stack_pop(ATEXIT_STACK); 411 if (func && unatexit(func) == 0) 412 func(); 413 } 414 } 415 416 static void fn_stack_push(fn_stack *st, AtExit_Fn_ptr func) { 417 fn_node *old_top, *n = (fn_node *)malloc(sizeof(fn_node)); 418 n->func = func; 419 420 while (1) { 421 old_top = st->top; 422 n->next = old_top; 423 if (COMPILER_RT_BOOL_CMPXCHG(&st->top, old_top, n)) 424 return; 425 } 426 } 427 static AtExit_Fn_ptr fn_stack_pop(fn_stack *st) { 428 fn_node *old_top, *new_top; 429 while (1) { 430 old_top = st->top; 431 if (old_top == 0) 432 return 0; 433 new_top = old_top->next; 434 if (COMPILER_RT_BOOL_CMPXCHG(&st->top, old_top, new_top)) { 435 AtExit_Fn_ptr func = old_top->func; 436 free(old_top); 437 return func; 438 } 439 } 440 } 441 442 static int fn_stack_is_empty(fn_stack *st) { return st->top == 0; } 443 #endif 444 445 COMPILER_RT_VISIBILITY int lprofAtExit(AtExit_Fn_ptr func) { 446 #ifdef _AIX 447 fn_stack_push(ATEXIT_STACK, func); 448 #endif 449 return atexit(func); 450 } 451