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 #include "trusty.h"
17
18 #include <stddef.h>
19 #include <string.h>
20
21 namespace scudo {
22
bit_cast(const Source & S)23 template <class Dest, class Source> inline Dest bit_cast(const Source &S) {
24 static_assert(sizeof(Dest) == sizeof(Source), "");
25 Dest D;
26 memcpy(&D, &S, sizeof(D));
27 return D;
28 }
29
roundUpTo(uptr X,uptr Boundary)30 inline constexpr uptr roundUpTo(uptr X, uptr Boundary) {
31 return (X + Boundary - 1) & ~(Boundary - 1);
32 }
33
roundDownTo(uptr X,uptr Boundary)34 inline constexpr uptr roundDownTo(uptr X, uptr Boundary) {
35 return X & ~(Boundary - 1);
36 }
37
isAligned(uptr X,uptr Alignment)38 inline constexpr bool isAligned(uptr X, uptr Alignment) {
39 return (X & (Alignment - 1)) == 0;
40 }
41
Min(T A,T B)42 template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
43
Max(T A,T B)44 template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
45
Swap(T & A,T & B)46 template <class T> void Swap(T &A, T &B) {
47 T Tmp = A;
48 A = B;
49 B = Tmp;
50 }
51
isPowerOfTwo(uptr X)52 inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; }
53
getMostSignificantSetBitIndex(uptr X)54 inline uptr getMostSignificantSetBitIndex(uptr X) {
55 DCHECK_NE(X, 0U);
56 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
57 }
58
roundUpToPowerOfTwo(uptr Size)59 inline uptr roundUpToPowerOfTwo(uptr Size) {
60 DCHECK(Size);
61 if (isPowerOfTwo(Size))
62 return Size;
63 const uptr Up = getMostSignificantSetBitIndex(Size);
64 DCHECK_LT(Size, (1UL << (Up + 1)));
65 DCHECK_GT(Size, (1UL << Up));
66 return 1UL << (Up + 1);
67 }
68
getLeastSignificantSetBitIndex(uptr X)69 inline uptr getLeastSignificantSetBitIndex(uptr X) {
70 DCHECK_NE(X, 0U);
71 return static_cast<uptr>(__builtin_ctzl(X));
72 }
73
getLog2(uptr X)74 inline uptr getLog2(uptr X) {
75 DCHECK(isPowerOfTwo(X));
76 return getLeastSignificantSetBitIndex(X);
77 }
78
getRandomU32(u32 * State)79 inline u32 getRandomU32(u32 *State) {
80 // ANSI C linear congruential PRNG (16-bit output).
81 // return (*State = *State * 1103515245 + 12345) >> 16;
82 // XorShift (32-bit output).
83 *State ^= *State << 13;
84 *State ^= *State >> 17;
85 *State ^= *State << 5;
86 return *State;
87 }
88
getRandomModN(u32 * State,u32 N)89 inline u32 getRandomModN(u32 *State, u32 N) {
90 return getRandomU32(State) % N; // [0, N)
91 }
92
shuffle(T * A,u32 N,u32 * RandState)93 template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
94 if (N <= 1)
95 return;
96 u32 State = *RandState;
97 for (u32 I = N - 1; I > 0; I--)
98 Swap(A[I], A[getRandomModN(&State, I + 1)]);
99 *RandState = State;
100 }
101
102 // Hardware specific inlinable functions.
103
yieldProcessor(UNUSED u8 Count)104 inline void yieldProcessor(UNUSED u8 Count) {
105 #if defined(__i386__) || defined(__x86_64__)
106 __asm__ __volatile__("" ::: "memory");
107 for (u8 I = 0; I < Count; I++)
108 __asm__ __volatile__("pause");
109 #elif defined(__aarch64__) || defined(__arm__)
110 __asm__ __volatile__("" ::: "memory");
111 for (u8 I = 0; I < Count; I++)
112 __asm__ __volatile__("yield");
113 #endif
114 __asm__ __volatile__("" ::: "memory");
115 }
116
117 // Platform specific functions.
118
119 extern uptr PageSizeCached;
120 uptr getPageSizeSlow();
getPageSizeCached()121 inline uptr getPageSizeCached() {
122 // Bionic uses a hardcoded value.
123 if (SCUDO_ANDROID)
124 return 4096U;
125 if (LIKELY(PageSizeCached))
126 return PageSizeCached;
127 return getPageSizeSlow();
128 }
129
130 // Returns 0 if the number of CPUs could not be determined.
131 u32 getNumberOfCPUs();
132
133 const char *getEnv(const char *Name);
134
135 uptr GetRSS();
136
137 u64 getMonotonicTime();
138
139 u32 getThreadID();
140
141 // Our randomness gathering function is limited to 256 bytes to ensure we get
142 // as many bytes as requested, and avoid interruptions (on Linux).
143 constexpr uptr MaxRandomLength = 256U;
144 bool getRandom(void *Buffer, uptr Length, bool Blocking = false);
145
146 // Platform memory mapping functions.
147
148 #define MAP_ALLOWNOMEM (1U << 0)
149 #define MAP_NOACCESS (1U << 1)
150 #define MAP_RESIZABLE (1U << 2)
151 #define MAP_MEMTAG (1U << 3)
152 #define MAP_PRECOMMIT (1U << 4)
153
154 // Our platform memory mapping use is restricted to 3 scenarios:
155 // - reserve memory at a random address (MAP_NOACCESS);
156 // - commit memory in a previously reserved space;
157 // - commit memory at a random address.
158 // As such, only a subset of parameters combinations is valid, which is checked
159 // by the function implementation. The Data parameter allows to pass opaque
160 // platform specific data to the function.
161 // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified.
162 void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0,
163 MapPlatformData *Data = nullptr);
164
165 // Indicates that we are getting rid of the whole mapping, which might have
166 // further consequences on Data, depending on the platform.
167 #define UNMAP_ALL (1U << 0)
168
169 void unmap(void *Addr, uptr Size, uptr Flags = 0,
170 MapPlatformData *Data = nullptr);
171
172 void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
173 MapPlatformData *Data = nullptr);
174
175 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
176 MapPlatformData *Data = nullptr);
177
178 // Internal map & unmap fatal error. This must not call map(). SizeIfOOM shall
179 // hold the requested size on an out-of-memory error, 0 otherwise.
180 void NORETURN dieOnMapUnmapError(uptr SizeIfOOM = 0);
181
182 // Logging related functions.
183
184 void setAbortMessage(const char *Message);
185
186 struct BlockInfo {
187 uptr BlockBegin;
188 uptr BlockSize;
189 uptr RegionBegin;
190 uptr RegionEnd;
191 };
192
193 enum class Option : u8 {
194 ReleaseInterval, // Release to OS interval in milliseconds.
195 MemtagTuning, // Whether to tune tagging for UAF or overflow.
196 ThreadDisableMemInit, // Whether to disable automatic heap initialization and,
197 // where possible, memory tagging, on this thread.
198 MaxCacheEntriesCount, // Maximum number of blocks that can be cached.
199 MaxCacheEntrySize, // Maximum size of a block that can be cached.
200 MaxTSDsCount, // Number of usable TSDs for the shared registry.
201 };
202
203 constexpr unsigned char PatternFillByte = 0xAB;
204
205 enum FillContentsMode {
206 NoFill = 0,
207 ZeroFill = 1,
208 PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
209 // zero-initialized already.
210 };
211
212 } // namespace scudo
213
214 #endif // SCUDO_COMMON_H_
215