354 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#if defined(__linux__)10 11#include <cstddef>12#include <cstdint>13 14#include "config.h"15 16#ifdef HAVE_ELF_H17#include <elf.h>18#endif19 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#else40#error "For Linux or MacOS only"41#endif42 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 0x100061#else62#define MAP_ANONYMOUS 0x2063#endif64 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 072#define O_WRONLY 173#define O_RDWR 274#define O_CREAT 6475#define O_TRUNC 51276#define O_APPEND 102477 78// Functions that are required by freestanding environment. Compiler may79// 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 point124namespace {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 65138 139struct UtsNameTy {140 char sysname[_UTSNAME_LENGTH]; /* Operating system name (e.g., "Linux") */141 char nodename[_UTSNAME_LENGTH]; /* Name within "some implementation-defined142 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#else161#error "For AArch64/ARM64,X86_64 AND RISCV64 only."162#endif163 164constexpr uint32_t BufSize = 10240;165 166// Helper functions for writing strings to the .fdata file. We intentionally167// 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 to170/// 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 string190char *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(Haystack); i++) {222 if (Haystack[i] == Needle[0]) {223 for (j = 1; j < strLen(Needle); j++) {224 if (Haystack[i + j] != Needle[j])225 break;226 }227 if (j == strLen(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(Ptr, Msg, BufSize - 23);238 Ptr = intToStr(Ptr, Num, Base);239 Ptr = strCopy(Ptr, "\n");240 __write(2, Buf, Ptr - Buf);241}242 243void report(const char *Msg) { __write(2, Msg, strLen(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 else256 return 0;257 }258 return Res;259}260 261/// Starting from character at \p buf, find the longest consecutive sequence262/// of digits (0-9) and convert it to uint32_t. The converted value263/// is put into \p ret. \p end marks the end of the buffer to avoid buffer264/// 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(2, Msg, Size);282 __exit(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(Ptr, "Assertion failed: ");291 Ptr = strCopy(Ptr, Msg, BufSize - 40);292 Ptr = strCopy(Ptr, "\n");293 reportError(Buf, Ptr - Buf);294}295 296#define SIG_BLOCK 0297#define SIG_UNBLOCK 1298#define SIG_SETMASK 2299 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 Mutex311class Lock {312 Mutex &M;313 uint64_t SignalMask[1] = {};314 315public:316 Lock(Mutex &M) : M(M) {317 __sigprocmask(SIG_BLOCK, MaskAllSignals, SignalMask);318 while (!M.acquire()) {319 }320 }321 322 ~Lock() {323 M.release();324 __sigprocmask(SIG_SETMASK, SignalMask, nullptr);325 }326};327 328/// RAII wrapper for Mutex329class 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 namespace354