blob: 3f27a3d3e1b1e17faa3f5b516de7abff33fb4282 [file] [log] [blame]
Dynamic Tools Team517193e2019-09-11 14:48:41 +00001//===-- 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
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080022template <class Dest, class Source> inline Dest bit_cast(const Source &S) {
23 static_assert(sizeof(Dest) == sizeof(Source), "");
Dynamic Tools Team517193e2019-09-11 14:48:41 +000024 Dest D;
25 memcpy(&D, &S, sizeof(D));
26 return D;
27}
28
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080029inline constexpr uptr roundUpTo(uptr X, uptr Boundary) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000030 return (X + Boundary - 1) & ~(Boundary - 1);
31}
32
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080033inline constexpr uptr roundDownTo(uptr X, uptr Boundary) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000034 return X & ~(Boundary - 1);
35}
36
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080037inline constexpr bool isAligned(uptr X, uptr Alignment) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000038 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
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080051inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; }
Dynamic Tools Team517193e2019-09-11 14:48:41 +000052
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080053inline uptr getMostSignificantSetBitIndex(uptr X) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000054 DCHECK_NE(X, 0U);
55 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
56}
57
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080058inline uptr roundUpToPowerOfTwo(uptr Size) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000059 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
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080068inline uptr getLeastSignificantSetBitIndex(uptr X) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000069 DCHECK_NE(X, 0U);
70 return static_cast<uptr>(__builtin_ctzl(X));
71}
72
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080073inline uptr getLog2(uptr X) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000074 DCHECK(isPowerOfTwo(X));
75 return getLeastSignificantSetBitIndex(X);
76}
77
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080078inline u32 getRandomU32(u32 *State) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000079 // 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
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080088inline u32 getRandomModN(u32 *State, u32 N) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000089 return getRandomU32(State) % N; // [0, N)
90}
91
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080092template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000093 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
Dynamic Tools Team09e6d482019-11-26 18:18:14 -0800103inline void yieldProcessor(u8 Count) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000104#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();
Dynamic Tools Team09e6d482019-11-26 18:18:14 -0800120inline uptr getPageSizeCached() {
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000121 // Bionic uses a hardcoded value.
122 if (SCUDO_ANDROID)
123 return 4096U;
124 if (LIKELY(PageSizeCached))
125 return PageSizeCached;
126 return getPageSizeSlow();
127}
128
Dynamic Tools Team7fef7302020-01-20 09:50:22 -0800129// Returns 0 if the number of CPUs could not be determined.
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000130u32 getNumberOfCPUs();
131
132const char *getEnv(const char *Name);
133
134u64 getMonotonicTime();
135
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700136u32 getThreadID();
137
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000138// Our randomness gathering function is limited to 256 bytes to ensure we get
139// as many bytes as requested, and avoid interruptions (on Linux).
140constexpr uptr MaxRandomLength = 256U;
141bool 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)
Dynamic Tools Team48429c72019-12-04 17:46:15 -0800148#define MAP_MEMTAG (1U << 3)
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000149
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.
158void *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
165void unmap(void *Addr, uptr Size, uptr Flags = 0,
166 MapPlatformData *Data = nullptr);
167
Peter Collingbournecc3d4932020-12-21 18:39:03 -0800168void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
169 MapPlatformData *Data = nullptr);
170
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000171void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
172 MapPlatformData *Data = nullptr);
173
Kostya Kortchinsky4d022f52021-05-24 09:26:21 -0700174// Internal map & unmap fatal error. This must not call map(). SizeIfOOM shall
175// hold the requested size on an out-of-memory error, 0 otherwise.
176void NORETURN dieOnMapUnmapError(uptr SizeIfOOM = 0);
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000177
178// Logging related functions.
179
180void setAbortMessage(const char *Message);
181
Dynamic Tools Team0d7d2ae2020-04-21 15:30:50 -0700182struct BlockInfo {
183 uptr BlockBegin;
184 uptr BlockSize;
185 uptr RegionBegin;
186 uptr RegionEnd;
187};
188
Kostya Kortchinskyc72ca562020-07-27 09:13:42 -0700189enum class Option : u8 {
190 ReleaseInterval, // Release to OS interval in milliseconds.
191 MemtagTuning, // Whether to tune tagging for UAF or overflow.
Peter Collingbourne33f8e1a2020-09-09 19:15:26 -0700192 ThreadDisableMemInit, // Whether to disable automatic heap initialization and,
193 // where possible, memory tagging, on this thread.
Kostya Kortchinskyc72ca562020-07-27 09:13:42 -0700194 MaxCacheEntriesCount, // Maximum number of blocks that can be cached.
195 MaxCacheEntrySize, // Maximum size of a block that can be cached.
196 MaxTSDsCount, // Number of usable TSDs for the shared registry.
197};
198
Dynamic Tools Team90d0d182020-04-29 14:39:23 -0700199constexpr unsigned char PatternFillByte = 0xAB;
200
201enum FillContentsMode {
202 NoFill = 0,
203 ZeroFill = 1,
204 PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
205 // zero-initialized already.
206};
207
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000208} // namespace scudo
209
210#endif // SCUDO_COMMON_H_