xref: /llvm-project/bolt/runtime/common.h (revision 87e9c42495aa4d290b04fa2866ec0e627a54842a)
1 //===- bolt/runtime/common.h ------------------------------------*- C++ -*-===//
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 
9 #if defined(__linux__)
10 
11 #include <cstddef>
12 #include <cstdint>
13 
14 #include "config.h"
15 
16 #ifdef HAVE_ELF_H
17 #include <elf.h>
18 #endif
19 
20 #elif defined(__APPLE__)
21 
22 typedef __SIZE_TYPE__ size_t;
23 #define __SSIZE_TYPE__                                                         \
24   __typeof__(_Generic((__SIZE_TYPE__)0, unsigned long long int                 \
25                       : (long long int)0, unsigned long int                    \
26                       : (long int)0, unsigned int                              \
27                       : (int)0, unsigned short                                 \
28                       : (short)0, unsigned char                                \
29                       : (signed char)0))
30 typedef __SSIZE_TYPE__ ssize_t;
31 
32 typedef unsigned long long uint64_t;
33 typedef unsigned uint32_t;
34 typedef unsigned char uint8_t;
35 
36 typedef long long int64_t;
37 typedef int int32_t;
38 
39 #else
40 #error "For Linux or MacOS only"
41 #endif
42 
43 #define PROT_READ 0x1  /* Page can be read.  */
44 #define PROT_WRITE 0x2 /* Page can be written.  */
45 #define PROT_EXEC 0x4  /* Page can be executed.  */
46 #define PROT_NONE 0x0  /* Page can not be accessed.  */
47 #define PROT_GROWSDOWN                                                         \
48   0x01000000 /* Extend change to start of                                      \
49                 growsdown vma (mprotect only).  */
50 #define PROT_GROWSUP                                                           \
51   0x02000000 /* Extend change to start of                                      \
52                 growsup vma (mprotect only).  */
53 
54 /* Sharing types (must choose one and only one of these).  */
55 #define MAP_SHARED 0x01  /* Share changes.  */
56 #define MAP_PRIVATE 0x02 /* Changes are private.  */
57 #define MAP_FIXED 0x10   /* Interpret addr exactly.  */
58 
59 #if defined(__APPLE__)
60 #define MAP_ANONYMOUS 0x1000
61 #else
62 #define MAP_ANONYMOUS 0x20
63 #endif
64 
65 #define MAP_FAILED ((void *)-1)
66 
67 #define SEEK_SET 0 /* Seek from beginning of file.  */
68 #define SEEK_CUR 1 /* Seek from current position.  */
69 #define SEEK_END 2 /* Seek from end of file.  */
70 
71 #define O_RDONLY 0
72 #define O_WRONLY 1
73 #define O_RDWR 2
74 #define O_CREAT 64
75 #define O_TRUNC 512
76 #define O_APPEND 1024
77 
78 // Functions that are required by freestanding environment. Compiler may
79 // generate calls to these implicitly.
80 extern "C" {
memcpy(void * Dest,const void * Src,size_t Len)81 void *memcpy(void *Dest, const void *Src, size_t Len) {
82   uint8_t *d = static_cast<uint8_t *>(Dest);
83   const uint8_t *s = static_cast<const uint8_t *>(Src);
84   while (Len--)
85     *d++ = *s++;
86   return Dest;
87 }
88 
memmove(void * Dest,const void * Src,size_t Len)89 void *memmove(void *Dest, const void *Src, size_t Len) {
90   uint8_t *d = static_cast<uint8_t *>(Dest);
91   const uint8_t *s = static_cast<const uint8_t *>(Src);
92   if (d < s) {
93     while (Len--)
94       *d++ = *s++;
95   } else {
96     s += Len - 1;
97     d += Len - 1;
98     while (Len--)
99       *d-- = *s--;
100   }
101 
102   return Dest;
103 }
104 
memset(void * Buf,int C,size_t Size)105 void *memset(void *Buf, int C, size_t Size) {
106   char *S = (char *)Buf;
107   for (size_t I = 0; I < Size; ++I)
108     *S++ = C;
109   return Buf;
110 }
111 
memcmp(const void * s1,const void * s2,size_t n)112 int memcmp(const void *s1, const void *s2, size_t n) {
113   const uint8_t *c1 = static_cast<const uint8_t *>(s1);
114   const uint8_t *c2 = static_cast<const uint8_t *>(s2);
115   for (; n--; c1++, c2++) {
116     if (*c1 != *c2)
117       return *c1 < *c2 ? -1 : 1;
118   }
119   return 0;
120 }
121 } // extern "C"
122 
123 // Anonymous namespace covering everything but our library entry point
124 namespace {
125 
126 struct dirent64 {
127   uint64_t d_ino;          /* Inode number */
128   int64_t d_off;           /* Offset to next linux_dirent */
129   unsigned short d_reclen; /* Length of this linux_dirent */
130   unsigned char d_type;
131   char d_name[]; /* Filename (null-terminated) */
132                  /* length is actually (d_reclen - 2 -
133                    offsetof(struct linux_dirent, d_name)) */
134 };
135 
136 /* Length of the entries in `struct utsname' is 65.  */
137 #define _UTSNAME_LENGTH 65
138 
139 struct UtsNameTy {
140   char sysname[_UTSNAME_LENGTH];  /* Operating system name (e.g., "Linux") */
141   char nodename[_UTSNAME_LENGTH]; /* Name within "some implementation-defined
142                       network" */
143   char release[_UTSNAME_LENGTH]; /* Operating system release (e.g., "2.6.28") */
144   char version[_UTSNAME_LENGTH]; /* Operating system version */
145   char machine[_UTSNAME_LENGTH]; /* Hardware identifier */
146   char domainname[_UTSNAME_LENGTH]; /* NIS or YP domain name */
147 };
148 
149 struct timespec {
150   uint64_t tv_sec;  /* seconds */
151   uint64_t tv_nsec; /* nanoseconds */
152 };
153 
154 #if defined(__aarch64__)
155 #include "sys_aarch64.h"
156 #else
157 #include "sys_x86_64.h"
158 #endif
159 
160 constexpr uint32_t BufSize = 10240;
161 
162 // Helper functions for writing strings to the .fdata file. We intentionally
163 // avoid using libc names to make it clear it is our impl.
164 
165 /// Write number Num using Base to the buffer in OutBuf, returns a pointer to
166 /// the end of the string.
intToStr(char * OutBuf,uint64_t Num,uint32_t Base)167 char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) {
168   const char *Chars = "0123456789abcdef";
169   char Buf[21];
170   char *Ptr = Buf;
171   while (Num) {
172     *Ptr++ = *(Chars + (Num % Base));
173     Num /= Base;
174   }
175   if (Ptr == Buf) {
176     *OutBuf++ = '0';
177     return OutBuf;
178   }
179   while (Ptr != Buf)
180     *OutBuf++ = *--Ptr;
181 
182   return OutBuf;
183 }
184 
185 /// Copy Str to OutBuf, returns a pointer to the end of the copied string
186 char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) {
187   while (*Str) {
188     *OutBuf++ = *Str++;
189     if (--Size <= 0)
190       return OutBuf;
191   }
192   return OutBuf;
193 }
194 
195 /// Compare two strings, at most Num bytes.
strnCmp(const char * Str1,const char * Str2,size_t Num)196 int strnCmp(const char *Str1, const char *Str2, size_t Num) {
197   while (Num && *Str1 && (*Str1 == *Str2)) {
198     Num--;
199     Str1++;
200     Str2++;
201   }
202   if (Num == 0)
203     return 0;
204   return *(unsigned char *)Str1 - *(unsigned char *)Str2;
205 }
206 
strLen(const char * Str)207 uint32_t strLen(const char *Str) {
208   uint32_t Size = 0;
209   while (*Str++)
210     ++Size;
211   return Size;
212 }
213 
strStr(const char * const Haystack,const char * const Needle)214 void *strStr(const char *const Haystack, const char *const Needle) {
215   int j = 0;
216 
217   for (int i = 0; i < strLen(Haystack); i++) {
218     if (Haystack[i] == Needle[0]) {
219       for (j = 1; j < strLen(Needle); j++) {
220         if (Haystack[i + j] != Needle[j])
221           break;
222       }
223       if (j == strLen(Needle))
224         return (void *)&Haystack[i];
225     }
226   }
227   return nullptr;
228 }
229 
reportNumber(const char * Msg,uint64_t Num,uint32_t Base)230 void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
231   char Buf[BufSize];
232   char *Ptr = Buf;
233   Ptr = strCopy(Ptr, Msg, BufSize - 23);
234   Ptr = intToStr(Ptr, Num, Base);
235   Ptr = strCopy(Ptr, "\n");
236   __write(2, Buf, Ptr - Buf);
237 }
238 
report(const char * Msg)239 void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
240 
241 unsigned long hexToLong(const char *Str, char Terminator = '\0') {
242   unsigned long Res = 0;
243   while (*Str != Terminator) {
244     Res <<= 4;
245     if ('0' <= *Str && *Str <= '9')
246       Res += *Str++ - '0';
247     else if ('a' <= *Str && *Str <= 'f')
248       Res += *Str++ - 'a' + 10;
249     else if ('A' <= *Str && *Str <= 'F')
250       Res += *Str++ - 'A' + 10;
251     else
252       return 0;
253   }
254   return Res;
255 }
256 
257 /// Starting from character at \p buf, find the longest consecutive sequence
258 /// of digits (0-9) and convert it to uint32_t. The converted value
259 /// is put into \p ret. \p end marks the end of the buffer to avoid buffer
260 /// overflow. The function \returns whether a valid uint32_t value is found.
261 /// \p buf will be updated to the next character right after the digits.
scanUInt32(const char * & Buf,const char * End,uint32_t & Ret)262 static bool scanUInt32(const char *&Buf, const char *End, uint32_t &Ret) {
263   uint64_t Result = 0;
264   const char *OldBuf = Buf;
265   while (Buf < End && ((*Buf) >= '0' && (*Buf) <= '9')) {
266     Result = Result * 10 + (*Buf) - '0';
267     ++Buf;
268   }
269   if (OldBuf != Buf && Result <= 0xFFFFFFFFu) {
270     Ret = static_cast<uint32_t>(Result);
271     return true;
272   }
273   return false;
274 }
275 
reportError(const char * Msg,uint64_t Size)276 void reportError(const char *Msg, uint64_t Size) {
277   __write(2, Msg, Size);
278   __exit(1);
279 }
280 
assert(bool Assertion,const char * Msg)281 void assert(bool Assertion, const char *Msg) {
282   if (Assertion)
283     return;
284   char Buf[BufSize];
285   char *Ptr = Buf;
286   Ptr = strCopy(Ptr, "Assertion failed: ");
287   Ptr = strCopy(Ptr, Msg, BufSize - 40);
288   Ptr = strCopy(Ptr, "\n");
289   reportError(Buf, Ptr - Buf);
290 }
291 
292 #define SIG_BLOCK 0
293 #define SIG_UNBLOCK 1
294 #define SIG_SETMASK 2
295 
296 static const uint64_t MaskAllSignals[] = {-1ULL};
297 
298 class Mutex {
299   volatile bool InUse{false};
300 
301 public:
acquire()302   bool acquire() { return !__atomic_test_and_set(&InUse, __ATOMIC_ACQUIRE); }
release()303   void release() { __atomic_clear(&InUse, __ATOMIC_RELEASE); }
304 };
305 
306 /// RAII wrapper for Mutex
307 class Lock {
308   Mutex &M;
309   uint64_t SignalMask[1] = {};
310 
311 public:
Lock(Mutex & M)312   Lock(Mutex &M) : M(M) {
313     __sigprocmask(SIG_BLOCK, MaskAllSignals, SignalMask);
314     while (!M.acquire()) {
315     }
316   }
317 
~Lock()318   ~Lock() {
319     M.release();
320     __sigprocmask(SIG_SETMASK, SignalMask, nullptr);
321   }
322 };
323 
324 /// RAII wrapper for Mutex
325 class TryLock {
326   Mutex &M;
327   bool Locked = false;
328 
329 public:
TryLock(Mutex & M)330   TryLock(Mutex &M) : M(M) {
331     int Retry = 100;
332     while (--Retry && !M.acquire())
333       ;
334     if (Retry)
335       Locked = true;
336   }
isLocked()337   bool isLocked() { return Locked; }
338 
~TryLock()339   ~TryLock() {
340     if (isLocked())
341       M.release();
342   }
343 };
344 
alignTo(uint64_t Value,uint64_t Align)345 inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
346   return (Value + Align - 1) / Align * Align;
347 }
348 
349 } // anonymous namespace
350