Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingUtil.c
35233 views
/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\1|*2|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3|* See https://llvm.org/LICENSE.txt for license information.4|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5|*6\*===----------------------------------------------------------------------===*/78#ifdef _WIN329#include <direct.h>10#include <process.h>11#include <windows.h>12#include "WindowsMMap.h"13#else14#include <errno.h>15#include <fcntl.h>16#include <sys/file.h>17#include <sys/mman.h>18#include <sys/stat.h>19#include <sys/types.h>20#include <unistd.h>21#endif2223#ifdef COMPILER_RT_HAS_UNAME24#include <sys/utsname.h>25#endif2627#include <stdlib.h>28#include <string.h>2930#if defined(__linux__)31#include <signal.h>32#include <sys/prctl.h>33#endif3435#if defined(__Fuchsia__)36#include <zircon/process.h>37#include <zircon/syscalls.h>38#endif3940#if defined(__FreeBSD__)41#include <signal.h>42#include <sys/procctl.h>43#endif4445#include "InstrProfiling.h"46#include "InstrProfilingUtil.h"4748COMPILER_RT_VISIBILITY unsigned lprofDirMode = 0755;4950COMPILER_RT_VISIBILITY51void __llvm_profile_recursive_mkdir(char *path) {52int i;53int start = 1;5455#if defined(__ANDROID__) && defined(__ANDROID_API__) && \56defined(__ANDROID_API_FUTURE__) && \57__ANDROID_API__ == __ANDROID_API_FUTURE__58// Avoid spammy selinux denial messages in Android by not attempting to59// create directories in GCOV_PREFIX. These denials occur when creating (or60// even attempting to stat()) top-level directories like "/data".61//62// Do so by ignoring ${GCOV_PREFIX} when invoking mkdir().63const char *gcov_prefix = getenv("GCOV_PREFIX");64if (gcov_prefix != NULL) {65const int gcov_prefix_len = strlen(gcov_prefix);66if (strncmp(path, gcov_prefix, gcov_prefix_len) == 0)67start = gcov_prefix_len;68}69#endif7071for (i = start; path[i] != '\0'; ++i) {72char save = path[i];73if (!IS_DIR_SEPARATOR(path[i]))74continue;75path[i] = '\0';76#ifdef _WIN3277_mkdir(path);78#else79/* Some of these will fail, ignore it. */80mkdir(path, __llvm_profile_get_dir_mode());81#endif82path[i] = save;83}84}8586COMPILER_RT_VISIBILITY87void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }8889COMPILER_RT_VISIBILITY90unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }9192#if COMPILER_RT_HAS_ATOMICS != 193COMPILER_RT_VISIBILITY94uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {95void *R = *Ptr;96if (R == OldV) {97*Ptr = NewV;98return 1;99}100return 0;101}102COMPILER_RT_VISIBILITY103void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {104void *Old = *Mem;105*((char **)Mem) += ByteIncr;106return Old;107}108109#endif110111#ifdef _WIN32112COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {113WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];114DWORD BufferSize = sizeof(Buffer);115BOOL Result =116GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);117if (!Result)118return -1;119if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)120return -1;121return 0;122}123#elif defined(COMPILER_RT_HAS_UNAME)124COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {125struct utsname N;126int R = uname(&N);127if (R >= 0) {128strncpy(Name, N.nodename, Len);129return 0;130}131return R;132}133#endif134135COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {136#ifdef COMPILER_RT_HAS_FCNTL_LCK137struct flock s_flock;138139s_flock.l_whence = SEEK_SET;140s_flock.l_start = 0;141s_flock.l_len = 0; /* Until EOF. */142s_flock.l_pid = getpid();143s_flock.l_type = F_WRLCK;144145while (fcntl(fd, F_SETLKW, &s_flock) == -1) {146if (errno != EINTR) {147if (errno == ENOLCK) {148return -1;149}150break;151}152}153return 0;154#else155flock(fd, LOCK_EX);156return 0;157#endif158}159160COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {161#ifdef COMPILER_RT_HAS_FCNTL_LCK162struct flock s_flock;163164s_flock.l_whence = SEEK_SET;165s_flock.l_start = 0;166s_flock.l_len = 0; /* Until EOF. */167s_flock.l_pid = getpid();168s_flock.l_type = F_UNLCK;169170while (fcntl(fd, F_SETLKW, &s_flock) == -1) {171if (errno != EINTR) {172if (errno == ENOLCK) {173return -1;174}175break;176}177}178return 0;179#else180flock(fd, LOCK_UN);181return 0;182#endif183}184185COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {186int fd;187#if defined(_WIN32)188fd = _fileno(F);189#else190fd = fileno(F);191#endif192return lprofLockFd(fd);193}194195COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {196int fd;197#if defined(_WIN32)198fd = _fileno(F);199#else200fd = fileno(F);201#endif202return lprofUnlockFd(fd);203}204205COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {206FILE *f;207int fd;208#ifdef COMPILER_RT_HAS_FCNTL_LCK209fd = open(ProfileName, O_RDWR | O_CREAT, 0666);210if (fd < 0)211return NULL;212213if (lprofLockFd(fd) != 0)214PROF_WARN("Data may be corrupted during profile merging : %s\n",215"Fail to obtain file lock due to system limit.");216217f = fdopen(fd, "r+b");218#elif defined(_WIN32)219// FIXME: Use the wide variants to handle Unicode filenames.220HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE,221FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS,222FILE_ATTRIBUTE_NORMAL, 0);223if (h == INVALID_HANDLE_VALUE)224return NULL;225226fd = _open_osfhandle((intptr_t)h, 0);227if (fd == -1) {228CloseHandle(h);229return NULL;230}231232if (lprofLockFd(fd) != 0)233PROF_WARN("Data may be corrupted during profile merging : %s\n",234"Fail to obtain file lock due to system limit.");235236f = _fdopen(fd, "r+b");237if (f == 0) {238CloseHandle(h);239return NULL;240}241#else242/* Worst case no locking applied. */243PROF_WARN("Concurrent file access is not supported : %s\n",244"lack file locking");245fd = open(ProfileName, O_RDWR | O_CREAT, 0666);246if (fd < 0)247return NULL;248f = fdopen(fd, "r+b");249#endif250251return f;252}253254COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,255size_t *PrefixLen) {256const char *Prefix = getenv("GCOV_PREFIX");257const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");258259*PrefixLen = 0;260*PrefixStrip = 0;261if (Prefix == NULL || Prefix[0] == '\0')262return NULL;263264if (PrefixStripStr) {265*PrefixStrip = atoi(PrefixStripStr);266267/* Negative GCOV_PREFIX_STRIP values are ignored */268if (*PrefixStrip < 0)269*PrefixStrip = 0;270} else {271*PrefixStrip = 0;272}273*PrefixLen = strlen(Prefix);274275return Prefix;276}277278COMPILER_RT_VISIBILITY void279lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,280size_t PrefixLen, int PrefixStrip) {281282const char *Ptr;283int Level;284const char *StrippedPathStr = PathStr;285286for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {287if (*Ptr == '\0')288break;289290if (!IS_DIR_SEPARATOR(*Ptr))291continue;292293StrippedPathStr = Ptr;294++Level;295}296297memcpy(Dest, Prefix, PrefixLen);298299if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))300Dest[PrefixLen++] = DIR_SEPARATOR;301302memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);303}304305COMPILER_RT_VISIBILITY const char *306lprofFindFirstDirSeparator(const char *Path) {307const char *Sep = strchr(Path, DIR_SEPARATOR);308#if defined(DIR_SEPARATOR_2)309const char *Sep2 = strchr(Path, DIR_SEPARATOR_2);310if (Sep2 && (!Sep || Sep2 < Sep))311Sep = Sep2;312#endif313return Sep;314}315316COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {317const char *Sep = strrchr(Path, DIR_SEPARATOR);318#if defined(DIR_SEPARATOR_2)319const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2);320if (Sep2 && (!Sep || Sep2 > Sep))321Sep = Sep2;322#endif323return Sep;324}325326COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) {327#if defined(__linux__)328int PDeachSig = 0;329/* Temporarily suspend getting SIGKILL upon exit of the parent process. */330if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)331prctl(PR_SET_PDEATHSIG, 0);332return (PDeachSig == SIGKILL);333#elif defined(__FreeBSD__)334int PDeachSig = 0, PDisableSig = 0;335if (procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &PDeachSig) == 0 &&336PDeachSig == SIGKILL)337procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PDisableSig);338return (PDeachSig == SIGKILL);339#else340return 0;341#endif342}343344COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) {345#if defined(__linux__)346prctl(PR_SET_PDEATHSIG, SIGKILL);347#elif defined(__FreeBSD__)348int PEnableSig = SIGKILL;349procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PEnableSig);350#endif351}352353COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,354uintptr_t End) {355#if defined(__ve__)356// VE doesn't support madvise.357return 0;358#else359size_t PageSize = getpagesize();360uintptr_t BeginAligned = lprofRoundUpTo((uintptr_t)Begin, PageSize);361uintptr_t EndAligned = lprofRoundDownTo((uintptr_t)End, PageSize);362if (BeginAligned < EndAligned) {363#if defined(__Fuchsia__)364return _zx_vmar_op_range(_zx_vmar_root_self(), ZX_VMAR_OP_DECOMMIT,365(zx_vaddr_t)BeginAligned,366EndAligned - BeginAligned, NULL, 0);367#else368return madvise((void *)BeginAligned, EndAligned - BeginAligned,369MADV_DONTNEED);370#endif371}372return 0;373#endif374}375376377