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 #include "InstrProfilingUtil.h"
11 #include "InstrProfiling.h"
12 
13 #ifdef _WIN32
14 #include <direct.h>
15 #include <io.h>
16 #include <windows.h>
17 #else
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #endif
24 
25 #ifdef COMPILER_RT_HAS_UNAME
26 #include <sys/utsname.h>
27 #endif
28 
29 #include <stdlib.h>
30 #include <string.h>
31 
32 COMPILER_RT_VISIBILITY
33 void __llvm_profile_recursive_mkdir(char *path) {
34   int i;
35 
36   for (i = 1; path[i] != '\0'; ++i) {
37     char save = path[i];
38     if (!IS_DIR_SEPARATOR(path[i]))
39       continue;
40     path[i] = '\0';
41 #ifdef _WIN32
42     _mkdir(path);
43 #else
44     mkdir(path, 0755); /* Some of these will fail, ignore it. */
45 #endif
46     path[i] = save;
47   }
48 }
49 
50 #if COMPILER_RT_HAS_ATOMICS != 1
51 COMPILER_RT_VISIBILITY
52 uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
53   void *R = *Ptr;
54   if (R == OldV) {
55     *Ptr = NewV;
56     return 1;
57   }
58   return 0;
59 }
60 COMPILER_RT_VISIBILITY
61 void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
62   void *Old = *Mem;
63   *((char **)Mem) += ByteIncr;
64   return Old;
65 }
66 
67 #endif
68 
69 #ifdef COMPILER_RT_HAS_UNAME
70 COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
71   struct utsname N;
72   int R;
73   if (!(R = uname(&N)))
74     strncpy(Name, N.nodename, Len);
75   return R;
76 }
77 #endif
78 
79 COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
80   FILE *f;
81   int fd;
82 #ifdef COMPILER_RT_HAS_FCNTL_LCK
83   struct flock s_flock;
84 
85   s_flock.l_whence = SEEK_SET;
86   s_flock.l_start = 0;
87   s_flock.l_len = 0; /* Until EOF.  */
88   s_flock.l_pid = getpid();
89 
90   s_flock.l_type = F_WRLCK;
91   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
92   if (fd < 0)
93     return NULL;
94 
95   while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
96     if (errno != EINTR) {
97       if (errno == ENOLCK) {
98         PROF_WARN("Data may be corrupted during profile merging : %s\n",
99                   "Fail to obtain file lock due to system limit.");
100       }
101       break;
102     }
103   }
104 
105   f = fdopen(fd, "r+b");
106 #elif defined(_WIN32)
107   // FIXME: Use the wide variants to handle Unicode filenames.
108   HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
109                          OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
110   if (h == INVALID_HANDLE_VALUE)
111     return NULL;
112 
113   fd = _open_osfhandle((intptr_t)h, 0);
114   if (fd == -1) {
115     CloseHandle(h);
116     return NULL;
117   }
118 
119   f = _fdopen(fd, "r+b");
120   if (f == 0) {
121     CloseHandle(h);
122     return NULL;
123   }
124 #else
125   /* Worst case no locking applied.  */
126   PROF_WARN("Concurrent file access is not supported : %s\n",
127             "lack file locking");
128   fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
129   if (fd < 0)
130     return NULL;
131   f = fdopen(fd, "r+b");
132 #endif
133 
134   return f;
135 }
136 
137 COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
138                                                       size_t *PrefixLen) {
139   const char *Prefix = getenv("GCOV_PREFIX");
140   const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
141 
142   *PrefixLen = 0;
143   *PrefixStrip = 0;
144   if (Prefix == NULL || Prefix[0] == '\0')
145     return NULL;
146 
147   if (PrefixStripStr) {
148     *PrefixStrip = atoi(PrefixStripStr);
149 
150     /* Negative GCOV_PREFIX_STRIP values are ignored */
151     if (*PrefixStrip < 0)
152       *PrefixStrip = 0;
153   } else {
154     *PrefixStrip = 0;
155   }
156   *PrefixLen = strlen(Prefix);
157 
158   return Prefix;
159 }
160 
161 COMPILER_RT_VISIBILITY void
162 lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
163                      size_t PrefixLen, int PrefixStrip) {
164 
165   const char *Ptr;
166   int Level;
167   const char *StrippedPathStr = PathStr;
168 
169   for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
170     if (*Ptr == '\0')
171       break;
172 
173     if (!IS_DIR_SEPARATOR(*Ptr))
174       continue;
175 
176     StrippedPathStr = Ptr;
177     ++Level;
178   }
179 
180   memcpy(Dest, Prefix, PrefixLen);
181 
182   if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
183     Dest[PrefixLen++] = DIR_SEPARATOR;
184 
185   memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
186 }
187 
188 COMPILER_RT_VISIBILITY const char *
189 lprofFindFirstDirSeparator(const char *Path) {
190   const char *Sep;
191   Sep = strchr(Path, DIR_SEPARATOR);
192   if (Sep)
193     return Sep;
194 #if defined(DIR_SEPARATOR_2)
195   Sep = strchr(Path, DIR_SEPARATOR_2);
196 #endif
197   return Sep;
198 }
199 
200 COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
201   const char *Sep;
202   Sep = strrchr(Path, DIR_SEPARATOR);
203   if (Sep)
204     return Sep;
205 #if defined(DIR_SEPARATOR_2)
206   Sep = strrchr(Path, DIR_SEPARATOR_2);
207 #endif
208   return Sep;
209 }
210