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