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