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