xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/common.h (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
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