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
22typedef __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))
30typedef __SSIZE_TYPE__ ssize_t;
31
32typedef unsigned long long uint64_t;
33typedef unsigned uint32_t;
34typedef unsigned char uint8_t;
35
36typedef long long int64_t;
37typedef 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.
80extern "C" {
81void *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
89void *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
105void *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
112int 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
124namespace {
125
126struct 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
139struct 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
149struct timespec {
150 uint64_t tv_sec; /* seconds */
151 uint64_t tv_nsec; /* nanoseconds */
152};
153
154#if defined(__aarch64__) || defined(__arm64__)
155#include "sys_aarch64.h"
156#elif defined(__riscv)
157#include "sys_riscv64.h"
158#elif defined(__x86_64__)
159#include "sys_x86_64.h"
160#else
161#error "For AArch64/ARM64,X86_64 AND RISCV64 only."
162#endif
163
164constexpr uint32_t BufSize = 10240;
165
166// Helper functions for writing strings to the .fdata file. We intentionally
167// avoid using libc names to make it clear it is our impl.
168
169/// Write number Num using Base to the buffer in OutBuf, returns a pointer to
170/// the end of the string.
171char *intToStr(char *OutBuf, uint64_t Num, uint32_t Base) {
172 const char *Chars = "0123456789abcdef";
173 char Buf[21];
174 char *Ptr = Buf;
175 while (Num) {
176 *Ptr++ = *(Chars + (Num % Base));
177 Num /= Base;
178 }
179 if (Ptr == Buf) {
180 *OutBuf++ = '0';
181 return OutBuf;
182 }
183 while (Ptr != Buf)
184 *OutBuf++ = *--Ptr;
185
186 return OutBuf;
187}
188
189/// Copy Str to OutBuf, returns a pointer to the end of the copied string
190char *strCopy(char *OutBuf, const char *Str, int32_t Size = BufSize) {
191 while (*Str) {
192 *OutBuf++ = *Str++;
193 if (--Size <= 0)
194 return OutBuf;
195 }
196 return OutBuf;
197}
198
199/// Compare two strings, at most Num bytes.
200int strnCmp(const char *Str1, const char *Str2, size_t Num) {
201 while (Num && *Str1 && (*Str1 == *Str2)) {
202 Num--;
203 Str1++;
204 Str2++;
205 }
206 if (Num == 0)
207 return 0;
208 return *(unsigned char *)Str1 - *(unsigned char *)Str2;
209}
210
211uint32_t strLen(const char *Str) {
212 uint32_t Size = 0;
213 while (*Str++)
214 ++Size;
215 return Size;
216}
217
218void *strStr(const char *const Haystack, const char *const Needle) {
219 int j = 0;
220
221 for (int i = 0; i < strLen(Str: Haystack); i++) {
222 if (Haystack[i] == Needle[0]) {
223 for (j = 1; j < strLen(Str: Needle); j++) {
224 if (Haystack[i + j] != Needle[j])
225 break;
226 }
227 if (j == strLen(Str: Needle))
228 return (void *)&Haystack[i];
229 }
230 }
231 return nullptr;
232}
233
234void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
235 char Buf[BufSize];
236 char *Ptr = Buf;
237 Ptr = strCopy(OutBuf: Ptr, Str: Msg, Size: BufSize - 23);
238 Ptr = intToStr(OutBuf: Ptr, Num, Base);
239 Ptr = strCopy(OutBuf: Ptr, Str: "\n");
240 __write(fd: 2, buf: Buf, count: Ptr - Buf);
241}
242
243void report(const char *Msg) { __write(fd: 2, buf: Msg, count: strLen(Str: Msg)); }
244
245unsigned long hexToLong(const char *Str, char Terminator = '\0') {
246 unsigned long Res = 0;
247 while (*Str != Terminator) {
248 Res <<= 4;
249 if ('0' <= *Str && *Str <= '9')
250 Res += *Str++ - '0';
251 else if ('a' <= *Str && *Str <= 'f')
252 Res += *Str++ - 'a' + 10;
253 else if ('A' <= *Str && *Str <= 'F')
254 Res += *Str++ - 'A' + 10;
255 else
256 return 0;
257 }
258 return Res;
259}
260
261/// Starting from character at \p buf, find the longest consecutive sequence
262/// of digits (0-9) and convert it to uint32_t. The converted value
263/// is put into \p ret. \p end marks the end of the buffer to avoid buffer
264/// overflow. The function \returns whether a valid uint32_t value is found.
265/// \p buf will be updated to the next character right after the digits.
266static bool scanUInt32(const char *&Buf, const char *End, uint32_t &Ret) {
267 uint64_t Result = 0;
268 const char *OldBuf = Buf;
269 while (Buf < End && ((*Buf) >= '0' && (*Buf) <= '9')) {
270 Result = Result * 10 + (*Buf) - '0';
271 ++Buf;
272 }
273 if (OldBuf != Buf && Result <= 0xFFFFFFFFu) {
274 Ret = static_cast<uint32_t>(Result);
275 return true;
276 }
277 return false;
278}
279
280void reportError(const char *Msg, uint64_t Size) {
281 __write(fd: 2, buf: Msg, count: Size);
282 __exit(code: 1);
283}
284
285void assert(bool Assertion, const char *Msg) {
286 if (Assertion)
287 return;
288 char Buf[BufSize];
289 char *Ptr = Buf;
290 Ptr = strCopy(OutBuf: Ptr, Str: "Assertion failed: ");
291 Ptr = strCopy(OutBuf: Ptr, Str: Msg, Size: BufSize - 40);
292 Ptr = strCopy(OutBuf: Ptr, Str: "\n");
293 reportError(Msg: Buf, Size: Ptr - Buf);
294}
295
296#define SIG_BLOCK 0
297#define SIG_UNBLOCK 1
298#define SIG_SETMASK 2
299
300static const uint64_t MaskAllSignals[] = {-1ULL};
301
302class Mutex {
303 volatile bool InUse{false};
304
305public:
306 bool acquire() { return !__atomic_test_and_set(&InUse, __ATOMIC_ACQUIRE); }
307 void release() { __atomic_clear(&InUse, __ATOMIC_RELEASE); }
308};
309
310/// RAII wrapper for Mutex
311class Lock {
312 Mutex &M;
313 uint64_t SignalMask[1] = {};
314
315public:
316 Lock(Mutex &M) : M(M) {
317 __sigprocmask(SIG_BLOCK, set: MaskAllSignals, oldset: SignalMask);
318 while (!M.acquire()) {
319 }
320 }
321
322 ~Lock() {
323 M.release();
324 __sigprocmask(SIG_SETMASK, set: SignalMask, oldset: nullptr);
325 }
326};
327
328/// RAII wrapper for Mutex
329class TryLock {
330 Mutex &M;
331 bool Locked = false;
332
333public:
334 TryLock(Mutex &M) : M(M) {
335 int Retry = 100;
336 while (--Retry && !M.acquire())
337 ;
338 if (Retry)
339 Locked = true;
340 }
341 bool isLocked() { return Locked; }
342
343 ~TryLock() {
344 if (isLocked())
345 M.release();
346 }
347};
348
349inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
350 return (Value + Align - 1) / Align * Align;
351}
352
353} // anonymous namespace
354

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of bolt/runtime/common.h