1 //===-- 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 #ifndef SCUDO_COMMON_H_ 10 #define SCUDO_COMMON_H_ 11 12 #include "internal_defs.h" 13 14 #include "fuchsia.h" 15 #include "linux.h" 16 17 #include <stddef.h> 18 #include <string.h> 19 20 namespace scudo { 21 22 template <class Dest, class Source> inline Dest bit_cast(const Source &S) { 23 static_assert(sizeof(Dest) == sizeof(Source), ""); 24 Dest D; 25 memcpy(&D, &S, sizeof(D)); 26 return D; 27 } 28 29 inline constexpr uptr roundUpTo(uptr X, uptr Boundary) { 30 return (X + Boundary - 1) & ~(Boundary - 1); 31 } 32 33 inline constexpr uptr roundDownTo(uptr X, uptr Boundary) { 34 return X & ~(Boundary - 1); 35 } 36 37 inline constexpr bool isAligned(uptr X, uptr Alignment) { 38 return (X & (Alignment - 1)) == 0; 39 } 40 41 template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } 42 43 template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } 44 45 template <class T> void Swap(T &A, T &B) { 46 T Tmp = A; 47 A = B; 48 B = Tmp; 49 } 50 51 inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; } 52 53 inline uptr getMostSignificantSetBitIndex(uptr X) { 54 DCHECK_NE(X, 0U); 55 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); 56 } 57 58 inline uptr roundUpToPowerOfTwo(uptr Size) { 59 DCHECK(Size); 60 if (isPowerOfTwo(Size)) 61 return Size; 62 const uptr Up = getMostSignificantSetBitIndex(Size); 63 DCHECK_LT(Size, (1UL << (Up + 1))); 64 DCHECK_GT(Size, (1UL << Up)); 65 return 1UL << (Up + 1); 66 } 67 68 inline uptr getLeastSignificantSetBitIndex(uptr X) { 69 DCHECK_NE(X, 0U); 70 return static_cast<uptr>(__builtin_ctzl(X)); 71 } 72 73 inline uptr getLog2(uptr X) { 74 DCHECK(isPowerOfTwo(X)); 75 return getLeastSignificantSetBitIndex(X); 76 } 77 78 inline u32 getRandomU32(u32 *State) { 79 // ANSI C linear congruential PRNG (16-bit output). 80 // return (*State = *State * 1103515245 + 12345) >> 16; 81 // XorShift (32-bit output). 82 *State ^= *State << 13; 83 *State ^= *State >> 17; 84 *State ^= *State << 5; 85 return *State; 86 } 87 88 inline u32 getRandomModN(u32 *State, u32 N) { 89 return getRandomU32(State) % N; // [0, N) 90 } 91 92 template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) { 93 if (N <= 1) 94 return; 95 u32 State = *RandState; 96 for (u32 I = N - 1; I > 0; I--) 97 Swap(A[I], A[getRandomModN(&State, I + 1)]); 98 *RandState = State; 99 } 100 101 // Hardware specific inlinable functions. 102 103 inline void yieldProcessor(u8 Count) { 104 #if defined(__i386__) || defined(__x86_64__) 105 __asm__ __volatile__("" ::: "memory"); 106 for (u8 I = 0; I < Count; I++) 107 __asm__ __volatile__("pause"); 108 #elif defined(__aarch64__) || defined(__arm__) 109 __asm__ __volatile__("" ::: "memory"); 110 for (u8 I = 0; I < Count; I++) 111 __asm__ __volatile__("yield"); 112 #endif 113 __asm__ __volatile__("" ::: "memory"); 114 } 115 116 // Platform specific functions. 117 118 extern uptr PageSizeCached; 119 uptr getPageSizeSlow(); 120 inline uptr getPageSizeCached() { 121 // Bionic uses a hardcoded value. 122 if (SCUDO_ANDROID) 123 return 4096U; 124 if (LIKELY(PageSizeCached)) 125 return PageSizeCached; 126 return getPageSizeSlow(); 127 } 128 129 u32 getNumberOfCPUs(); 130 131 const char *getEnv(const char *Name); 132 133 u64 getMonotonicTime(); 134 135 // Our randomness gathering function is limited to 256 bytes to ensure we get 136 // as many bytes as requested, and avoid interruptions (on Linux). 137 constexpr uptr MaxRandomLength = 256U; 138 bool getRandom(void *Buffer, uptr Length, bool Blocking = false); 139 140 // Platform memory mapping functions. 141 142 #define MAP_ALLOWNOMEM (1U << 0) 143 #define MAP_NOACCESS (1U << 1) 144 #define MAP_RESIZABLE (1U << 2) 145 146 // Our platform memory mapping use is restricted to 3 scenarios: 147 // - reserve memory at a random address (MAP_NOACCESS); 148 // - commit memory in a previously reserved space; 149 // - commit memory at a random address. 150 // As such, only a subset of parameters combinations is valid, which is checked 151 // by the function implementation. The Data parameter allows to pass opaque 152 // platform specific data to the function. 153 // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. 154 void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, 155 MapPlatformData *Data = nullptr); 156 157 // Indicates that we are getting rid of the whole mapping, which might have 158 // further consequences on Data, depending on the platform. 159 #define UNMAP_ALL (1U << 0) 160 161 void unmap(void *Addr, uptr Size, uptr Flags = 0, 162 MapPlatformData *Data = nullptr); 163 164 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, 165 MapPlatformData *Data = nullptr); 166 167 // Internal map & unmap fatal error. This must not call map(). 168 void NORETURN dieOnMapUnmapError(bool OutOfMemory = false); 169 170 // Logging related functions. 171 172 void setAbortMessage(const char *Message); 173 174 } // namespace scudo 175 176 #endif // SCUDO_COMMON_H_ 177