1 //===-- common.h ------------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef SCUDO_COMMON_H_
10 #define SCUDO_COMMON_H_
12 #include "internal_defs.h"
22 template <class Dest, class Source> INLINE Dest bit_cast(const Source &S) {
23 COMPILER_CHECK(sizeof(Dest) == sizeof(Source));
25 memcpy(&D, &S, sizeof(D));
29 INLINE constexpr uptr roundUpTo(uptr X, uptr Boundary) {
30 return (X + Boundary - 1) & ~(Boundary - 1);
33 INLINE constexpr uptr roundDownTo(uptr X, uptr Boundary) {
34 return X & ~(Boundary - 1);
37 INLINE constexpr bool isAligned(uptr X, uptr Alignment) {
38 return (X & (Alignment - 1)) == 0;
41 template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
43 template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
45 template <class T> void Swap(T &A, T &B) {
51 INLINE bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; }
53 INLINE uptr getMostSignificantSetBitIndex(uptr X) {
55 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
58 INLINE uptr roundUpToPowerOfTwo(uptr Size) {
60 if (isPowerOfTwo(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);
68 INLINE uptr getLeastSignificantSetBitIndex(uptr X) {
70 return static_cast<uptr>(__builtin_ctzl(X));
73 INLINE uptr getLog2(uptr X) {
74 DCHECK(isPowerOfTwo(X));
75 return getLeastSignificantSetBitIndex(X);
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;
88 INLINE u32 getRandomModN(u32 *State, u32 N) {
89 return getRandomU32(State) % N; // [0, N)
92 template <typename T> INLINE void shuffle(T *A, u32 N, u32 *RandState) {
95 u32 State = *RandState;
96 for (u32 I = N - 1; I > 0; I--)
97 Swap(A[I], A[getRandomModN(&State, I + 1)]);
101 // Hardware specific inlinable functions.
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");
113 __asm__ __volatile__("" ::: "memory");
116 // Platform specific functions.
118 extern uptr PageSizeCached;
119 uptr getPageSizeSlow();
120 INLINE uptr getPageSizeCached() {
121 // Bionic uses a hardcoded value.
124 if (LIKELY(PageSizeCached))
125 return PageSizeCached;
126 return getPageSizeSlow();
129 u32 getNumberOfCPUs();
131 const char *getEnv(const char *Name);
133 u64 getMonotonicTime();
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);
140 // Platform memory mapping functions.
142 #define MAP_ALLOWNOMEM (1U << 0)
143 #define MAP_NOACCESS (1U << 1)
144 #define MAP_RESIZABLE (1U << 2)
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);
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)
161 void unmap(void *Addr, uptr Size, uptr Flags = 0,
162 MapPlatformData *Data = nullptr);
164 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
165 MapPlatformData *Data = nullptr);
167 // Internal map & unmap fatal error. This must not call map().
168 void NORETURN dieOnMapUnmapError(bool OutOfMemory = false);
170 // Logging related functions.
172 void setAbortMessage(const char *Message);
176 #endif // SCUDO_COMMON_H_