| 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" { |
| 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 | |
| 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 | |
| 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 | |
| 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__) || 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 | |
| 164 | constexpr 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. |
| 171 | char *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 |
| 190 | char *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. |
| 200 | int 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 | |
| 211 | uint32_t strLen(const char *Str) { |
| 212 | uint32_t Size = 0; |
| 213 | while (*Str++) |
| 214 | ++Size; |
| 215 | return Size; |
| 216 | } |
| 217 | |
| 218 | void *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 | |
| 234 | void 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 | |
| 243 | void report(const char *Msg) { __write(fd: 2, buf: Msg, count: strLen(Str: Msg)); } |
| 244 | |
| 245 | unsigned 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. |
| 266 | static 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 | |
| 280 | void reportError(const char *Msg, uint64_t Size) { |
| 281 | __write(fd: 2, buf: Msg, count: Size); |
| 282 | __exit(code: 1); |
| 283 | } |
| 284 | |
| 285 | void 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 | |
| 300 | static const uint64_t MaskAllSignals[] = {-1ULL}; |
| 301 | |
| 302 | class Mutex { |
| 303 | volatile bool InUse{false}; |
| 304 | |
| 305 | public: |
| 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 |
| 311 | class Lock { |
| 312 | Mutex &M; |
| 313 | uint64_t SignalMask[1] = {}; |
| 314 | |
| 315 | public: |
| 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 |
| 329 | class TryLock { |
| 330 | Mutex &M; |
| 331 | bool Locked = false; |
| 332 | |
| 333 | public: |
| 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 | |
| 349 | inline uint64_t alignTo(uint64_t Value, uint64_t Align) { |
| 350 | return (Value + Align - 1) / Align * Align; |
| 351 | } |
| 352 | |
| 353 | } // anonymous namespace |
| 354 | |