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 // Returns 0 if the number of CPUs could not be determined. 130 u32 getNumberOfCPUs(); 131 132 const char *getEnv(const char *Name); 133 134 u64 getMonotonicTime(); 135 136 u32 getThreadID(); 137 138 // Our randomness gathering function is limited to 256 bytes to ensure we get 139 // as many bytes as requested, and avoid interruptions (on Linux). 140 constexpr uptr MaxRandomLength = 256U; 141 bool getRandom(void *Buffer, uptr Length, bool Blocking = false); 142 143 // Platform memory mapping functions. 144 145 #define MAP_ALLOWNOMEM (1U << 0) 146 #define MAP_NOACCESS (1U << 1) 147 #define MAP_RESIZABLE (1U << 2) 148 #define MAP_MEMTAG (1U << 3) 149 150 // Our platform memory mapping use is restricted to 3 scenarios: 151 // - reserve memory at a random address (MAP_NOACCESS); 152 // - commit memory in a previously reserved space; 153 // - commit memory at a random address. 154 // As such, only a subset of parameters combinations is valid, which is checked 155 // by the function implementation. The Data parameter allows to pass opaque 156 // platform specific data to the function. 157 // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. 158 void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, 159 MapPlatformData *Data = nullptr); 160 161 // Indicates that we are getting rid of the whole mapping, which might have 162 // further consequences on Data, depending on the platform. 163 #define UNMAP_ALL (1U << 0) 164 165 void unmap(void *Addr, uptr Size, uptr Flags = 0, 166 MapPlatformData *Data = nullptr); 167 168 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, 169 MapPlatformData *Data = nullptr); 170 171 // Internal map & unmap fatal error. This must not call map(). 172 void NORETURN dieOnMapUnmapError(bool OutOfMemory = false); 173 174 // Logging related functions. 175 176 void setAbortMessage(const char *Message); 177 178 struct BlockInfo { 179 uptr BlockBegin; 180 uptr BlockSize; 181 uptr RegionBegin; 182 uptr RegionEnd; 183 }; 184 185 constexpr unsigned char PatternFillByte = 0xAB; 186 187 enum FillContentsMode { 188 NoFill = 0, 189 ZeroFill = 1, 190 PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be 191 // zero-initialized already. 192 }; 193 194 } // namespace scudo 195 196 #endif // SCUDO_COMMON_H_ 197