common.h revision 360784
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 20namespace scudo { 21 22template <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 29inline constexpr uptr roundUpTo(uptr X, uptr Boundary) { 30 return (X + Boundary - 1) & ~(Boundary - 1); 31} 32 33inline constexpr uptr roundDownTo(uptr X, uptr Boundary) { 34 return X & ~(Boundary - 1); 35} 36 37inline constexpr bool isAligned(uptr X, uptr Alignment) { 38 return (X & (Alignment - 1)) == 0; 39} 40 41template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } 42 43template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } 44 45template <class T> void Swap(T &A, T &B) { 46 T Tmp = A; 47 A = B; 48 B = Tmp; 49} 50 51inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; } 52 53inline uptr getMostSignificantSetBitIndex(uptr X) { 54 DCHECK_NE(X, 0U); 55 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); 56} 57 58inline 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 68inline uptr getLeastSignificantSetBitIndex(uptr X) { 69 DCHECK_NE(X, 0U); 70 return static_cast<uptr>(__builtin_ctzl(X)); 71} 72 73inline uptr getLog2(uptr X) { 74 DCHECK(isPowerOfTwo(X)); 75 return getLeastSignificantSetBitIndex(X); 76} 77 78inline 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 88inline u32 getRandomModN(u32 *State, u32 N) { 89 return getRandomU32(State) % N; // [0, N) 90} 91 92template <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 103inline 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 118extern uptr PageSizeCached; 119uptr getPageSizeSlow(); 120inline 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 129u32 getNumberOfCPUs(); 130 131const char *getEnv(const char *Name); 132 133u64 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). 137constexpr uptr MaxRandomLength = 256U; 138bool 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. 154void *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 161void unmap(void *Addr, uptr Size, uptr Flags = 0, 162 MapPlatformData *Data = nullptr); 163 164void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, 165 MapPlatformData *Data = nullptr); 166 167// Internal map & unmap fatal error. This must not call map(). 168void NORETURN dieOnMapUnmapError(bool OutOfMemory = false); 169 170// Logging related functions. 171 172void setAbortMessage(const char *Message); 173 174} // namespace scudo 175 176#endif // SCUDO_COMMON_H_ 177