InstrProfilingUtil.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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. #ifdef _WIN32
  9. #include <direct.h>
  10. #include <process.h>
  11. #include <windows.h>
  12. #include "WindowsMMap.h"
  13. #else
  14. #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. #endif
  22. #ifdef COMPILER_RT_HAS_UNAME
  23. #include <sys/utsname.h>
  24. #endif
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #if defined(__linux__)
  28. #include <signal.h>
  29. #include <sys/prctl.h>
  30. #endif
  31. #if defined(__Fuchsia__)
  32. #error #include <zircon/process.h>
  33. #error #include <zircon/syscalls.h>
  34. #endif
  35. #if defined(__FreeBSD__)
  36. #include <signal.h>
  37. #error #include <sys/procctl.h>
  38. #endif
  39. #include "InstrProfiling.h"
  40. #include "InstrProfilingUtil.h"
  41. COMPILER_RT_VISIBILITY unsigned lprofDirMode = 0755;
  42. COMPILER_RT_VISIBILITY
  43. void __llvm_profile_recursive_mkdir(char *path) {
  44. int i;
  45. int start = 1;
  46. #if defined(__ANDROID__) && defined(__ANDROID_API__) && \
  47. defined(__ANDROID_API_FUTURE__) && \
  48. __ANDROID_API__ == __ANDROID_API_FUTURE__
  49. // Avoid spammy selinux denial messages in Android by not attempting to
  50. // create directories in GCOV_PREFIX. These denials occur when creating (or
  51. // even attempting to stat()) top-level directories like "/data".
  52. //
  53. // Do so by ignoring ${GCOV_PREFIX} when invoking mkdir().
  54. const char *gcov_prefix = getenv("GCOV_PREFIX");
  55. if (gcov_prefix != NULL) {
  56. const int gcov_prefix_len = strlen(gcov_prefix);
  57. if (strncmp(path, gcov_prefix, gcov_prefix_len) == 0)
  58. start = gcov_prefix_len;
  59. }
  60. #endif
  61. for (i = start; path[i] != '\0'; ++i) {
  62. char save = path[i];
  63. if (!IS_DIR_SEPARATOR(path[i]))
  64. continue;
  65. path[i] = '\0';
  66. #ifdef _WIN32
  67. _mkdir(path);
  68. #else
  69. /* Some of these will fail, ignore it. */
  70. mkdir(path, __llvm_profile_get_dir_mode());
  71. #endif
  72. path[i] = save;
  73. }
  74. }
  75. COMPILER_RT_VISIBILITY
  76. void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
  77. COMPILER_RT_VISIBILITY
  78. unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
  79. #if COMPILER_RT_HAS_ATOMICS != 1
  80. COMPILER_RT_VISIBILITY
  81. uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
  82. void *R = *Ptr;
  83. if (R == OldV) {
  84. *Ptr = NewV;
  85. return 1;
  86. }
  87. return 0;
  88. }
  89. COMPILER_RT_VISIBILITY
  90. void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
  91. void *Old = *Mem;
  92. *((char **)Mem) += ByteIncr;
  93. return Old;
  94. }
  95. #endif
  96. #ifdef _WIN32
  97. COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
  98. WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
  99. DWORD BufferSize = sizeof(Buffer);
  100. BOOL Result =
  101. GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
  102. if (!Result)
  103. return -1;
  104. if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
  105. return -1;
  106. return 0;
  107. }
  108. #elif defined(COMPILER_RT_HAS_UNAME)
  109. COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
  110. struct utsname N;
  111. int R = uname(&N);
  112. if (R >= 0) {
  113. strncpy(Name, N.nodename, Len);
  114. return 0;
  115. }
  116. return R;
  117. }
  118. #endif
  119. COMPILER_RT_VISIBILITY int lprofLockFd(int fd) {
  120. #ifdef COMPILER_RT_HAS_FCNTL_LCK
  121. struct flock s_flock;
  122. s_flock.l_whence = SEEK_SET;
  123. s_flock.l_start = 0;
  124. s_flock.l_len = 0; /* Until EOF. */
  125. s_flock.l_pid = getpid();
  126. s_flock.l_type = F_WRLCK;
  127. while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
  128. if (errno != EINTR) {
  129. if (errno == ENOLCK) {
  130. return -1;
  131. }
  132. break;
  133. }
  134. }
  135. return 0;
  136. #else
  137. flock(fd, LOCK_EX);
  138. return 0;
  139. #endif
  140. }
  141. COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) {
  142. #ifdef COMPILER_RT_HAS_FCNTL_LCK
  143. struct flock s_flock;
  144. s_flock.l_whence = SEEK_SET;
  145. s_flock.l_start = 0;
  146. s_flock.l_len = 0; /* Until EOF. */
  147. s_flock.l_pid = getpid();
  148. s_flock.l_type = F_UNLCK;
  149. while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
  150. if (errno != EINTR) {
  151. if (errno == ENOLCK) {
  152. return -1;
  153. }
  154. break;
  155. }
  156. }
  157. return 0;
  158. #else
  159. flock(fd, LOCK_UN);
  160. return 0;
  161. #endif
  162. }
  163. COMPILER_RT_VISIBILITY int lprofLockFileHandle(FILE *F) {
  164. int fd;
  165. #if defined(_WIN32)
  166. fd = _fileno(F);
  167. #else
  168. fd = fileno(F);
  169. #endif
  170. return lprofLockFd(fd);
  171. }
  172. COMPILER_RT_VISIBILITY int lprofUnlockFileHandle(FILE *F) {
  173. int fd;
  174. #if defined(_WIN32)
  175. fd = _fileno(F);
  176. #else
  177. fd = fileno(F);
  178. #endif
  179. return lprofUnlockFd(fd);
  180. }
  181. COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
  182. FILE *f;
  183. int fd;
  184. #ifdef COMPILER_RT_HAS_FCNTL_LCK
  185. fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  186. if (fd < 0)
  187. return NULL;
  188. if (lprofLockFd(fd) != 0)
  189. PROF_WARN("Data may be corrupted during profile merging : %s\n",
  190. "Fail to obtain file lock due to system limit.");
  191. f = fdopen(fd, "r+b");
  192. #elif defined(_WIN32)
  193. // FIXME: Use the wide variants to handle Unicode filenames.
  194. HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE,
  195. FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
  196. FILE_ATTRIBUTE_NORMAL, 0);
  197. if (h == INVALID_HANDLE_VALUE)
  198. return NULL;
  199. fd = _open_osfhandle((intptr_t)h, 0);
  200. if (fd == -1) {
  201. CloseHandle(h);
  202. return NULL;
  203. }
  204. if (lprofLockFd(fd) != 0)
  205. PROF_WARN("Data may be corrupted during profile merging : %s\n",
  206. "Fail to obtain file lock due to system limit.");
  207. f = _fdopen(fd, "r+b");
  208. if (f == 0) {
  209. CloseHandle(h);
  210. return NULL;
  211. }
  212. #else
  213. /* Worst case no locking applied. */
  214. PROF_WARN("Concurrent file access is not supported : %s\n",
  215. "lack file locking");
  216. fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  217. if (fd < 0)
  218. return NULL;
  219. f = fdopen(fd, "r+b");
  220. #endif
  221. return f;
  222. }
  223. COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
  224. size_t *PrefixLen) {
  225. const char *Prefix = getenv("GCOV_PREFIX");
  226. const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
  227. *PrefixLen = 0;
  228. *PrefixStrip = 0;
  229. if (Prefix == NULL || Prefix[0] == '\0')
  230. return NULL;
  231. if (PrefixStripStr) {
  232. *PrefixStrip = atoi(PrefixStripStr);
  233. /* Negative GCOV_PREFIX_STRIP values are ignored */
  234. if (*PrefixStrip < 0)
  235. *PrefixStrip = 0;
  236. } else {
  237. *PrefixStrip = 0;
  238. }
  239. *PrefixLen = strlen(Prefix);
  240. return Prefix;
  241. }
  242. COMPILER_RT_VISIBILITY void
  243. lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
  244. size_t PrefixLen, int PrefixStrip) {
  245. const char *Ptr;
  246. int Level;
  247. const char *StrippedPathStr = PathStr;
  248. for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
  249. if (*Ptr == '\0')
  250. break;
  251. if (!IS_DIR_SEPARATOR(*Ptr))
  252. continue;
  253. StrippedPathStr = Ptr;
  254. ++Level;
  255. }
  256. memcpy(Dest, Prefix, PrefixLen);
  257. if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
  258. Dest[PrefixLen++] = DIR_SEPARATOR;
  259. memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
  260. }
  261. COMPILER_RT_VISIBILITY const char *
  262. lprofFindFirstDirSeparator(const char *Path) {
  263. const char *Sep = strchr(Path, DIR_SEPARATOR);
  264. #if defined(DIR_SEPARATOR_2)
  265. const char *Sep2 = strchr(Path, DIR_SEPARATOR_2);
  266. if (Sep2 && (!Sep || Sep2 < Sep))
  267. Sep = Sep2;
  268. #endif
  269. return Sep;
  270. }
  271. COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
  272. const char *Sep = strrchr(Path, DIR_SEPARATOR);
  273. #if defined(DIR_SEPARATOR_2)
  274. const char *Sep2 = strrchr(Path, DIR_SEPARATOR_2);
  275. if (Sep2 && (!Sep || Sep2 > Sep))
  276. Sep = Sep2;
  277. #endif
  278. return Sep;
  279. }
  280. COMPILER_RT_VISIBILITY int lprofSuspendSigKill(void) {
  281. #if defined(__linux__)
  282. int PDeachSig = 0;
  283. /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
  284. if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
  285. prctl(PR_SET_PDEATHSIG, 0);
  286. return (PDeachSig == SIGKILL);
  287. #elif defined(__FreeBSD__)
  288. int PDeachSig = 0, PDisableSig = 0;
  289. if (procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &PDeachSig) == 0 &&
  290. PDeachSig == SIGKILL)
  291. procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PDisableSig);
  292. return (PDeachSig == SIGKILL);
  293. #else
  294. return 0;
  295. #endif
  296. }
  297. COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) {
  298. #if defined(__linux__)
  299. prctl(PR_SET_PDEATHSIG, SIGKILL);
  300. #elif defined(__FreeBSD__)
  301. int PEnableSig = SIGKILL;
  302. procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &PEnableSig);
  303. #endif
  304. }
  305. COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,
  306. uintptr_t End) {
  307. #if defined(__ve__)
  308. // VE doesn't support madvise.
  309. return 0;
  310. #else
  311. size_t PageSize = getpagesize();
  312. uintptr_t BeginAligned = lprofRoundUpTo((uintptr_t)Begin, PageSize);
  313. uintptr_t EndAligned = lprofRoundDownTo((uintptr_t)End, PageSize);
  314. if (BeginAligned < EndAligned) {
  315. #if defined(__Fuchsia__)
  316. return _zx_vmar_op_range(_zx_vmar_root_self(), ZX_VMAR_OP_DECOMMIT,
  317. (zx_vaddr_t)BeginAligned,
  318. EndAligned - BeginAligned, NULL, 0);
  319. #else
  320. return madvise((void *)BeginAligned, EndAligned - BeginAligned,
  321. MADV_DONTNEED);
  322. #endif
  323. }
  324. return 0;
  325. #endif
  326. }